零碎汇总
- ‘debug‘的值默认是True,且是只读,py2.7中还是无法修改的值。
- python常见的数据类型是数字,字符串,列表,字典,集合,元组等,常见的语法是条件,循环,列表解析,函数等。组合起来是python的基本要素。
- ‘str‘方法:是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
class UseInt(object):
def __init__(self, val):
self._val = val
def __str__(self):
return self._val
name = 'hello, chen'
result = UseInt(name)
print(result)
输出是:
hello, chen
Process finished with exit code 0
如果是没有加上'__str__'方法,则显示的是对象地址:
<__main__.UseInt object at 0x000001F81DBF9908>
Process finished with exit code 0
```注意:```
```'__repr__'方法和'__str__'方法是同样作用```,但是如果同时存在,则只会输出str方法中的返回内容:
class UseInt(object):
def __init__(self, val):
self._val = val
def __repr__(self):
return self._val + ', this is REPR funcation'
def __str__(self):
return self._val + ', this is STR funcation'
def __add__(self, other):
return self._val + other
name = 'hello, chen'
result = UseInt(name)
print(result)
输出:
hello, chen, this is str funcation
Process finished with exit code 0
3. '__add__'方法: 在使用'+'进行相加的时候,会自动的调用该方法:
class UseInt(object):
def __init__(self, val):
self._val = val
def __str__(self):
return self._val
def __add__(self, other):
return self._val + other
name = 'hello, chen'
result = UseInt(name)
print(result + ', how do you do')
输出是:
hello, chen, how do you do
Process finished with exit code 0
如果其中,add的是不同数据类型,则,会报类型异常错误。
4. math.pow方法:math.pow(x, y) 返回的是x的y次方
#### 建议6:编写函数的4个原则
* 函数设计要尽量短小,嵌套层次不易过深。
* 函数申明应该做到合理,简单,易于使用。函数名争取的反应其大体的功能,参数个数不宜过多。
* 函数参数设计应该考虑向下兼容。
* 一个函数只做一件事,尽量保证函数语句的粒度一致性。
#### 建议7:将常量集中到一个文件中
## 编程惯用法
#### 建议8:利用assert语句发现问题
assert主要是为了调试程序,判断表达式1是否成立。如果不成立,则抛出AssertionError异常,异常内容为表达式2,表达式2为可选。用法为:
assert 表达式1 [, 表达式2] # 逗号是分隔二个表达式的
使用例子:
In [1]: x = 1
In [2]: y = 2
In [3]: assert x == y, 'Not Equals'
--------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-3-58ccfd0f1c7f> in <module>()
----> 1 assert x == y, 'Not Equals'
AssertionError: Not Equals
Python中断言是会对性能产生一定的影响,通常禁用断言的方式是执行的时候加上-O标志。这种方式带来的影响是它并不是优化字节码,而是忽略与断言相关的语句。 python -O filename.py 便可断言。
断言的使用:
1. 不要滥用。
2. 如果是python本身的异常,就不要再使用断言,例如类型不对,除数为0等。断言是判断自己写的代码是否会出现异常。
3. 不要使用断言判断是用户的输入。
4. 函数调用后,判断函数你返回值是否合理的时候,可以使用。
5. 当条件是业务逻辑继续下去的先决条件时可以使用。
#### 建议9:数据交换时不推荐使用中间变量
要使用Pythonic的方式实现:
x, y = y, x
首先通过耗时来测试:
In [12]: from timeit import Timer
In [13]: Timer('temp=x; x=y; y=temp', 'x=2; y=3').timeit()
Out[13]: 0.050784500556474654
In [14]: Timer('x, y=y, x', 'x=1; y=2').timeit()
Out[14]: 0.03139274866055075
明显的使用Pythonic方式耗时会更短。
#### 建议10:充分利用Lazy evaluation特性
Lazy evaluation为惰性计算,指的是仅仅在需要执行的时候才计算表达式的值。好处体现在:
1. 避免不必要的计算,提升性能。
对于条件表达式 ```if x and y```,在x为False时,y表达式将不会再进行计算;对于表达式```if x or y```, x为True时,将直接返回,不再计算y的值。所以,or条件表达式将真值可能性较高的放在前面,而and表达式,真值可能性高的放在后面。
2. 节省空间,使得无限循环的数据结构成为可能。
最典型的是生成器表达式,仅在需要计算的时候才通过yield产生所需的元素。斐波那契数列可以借此完成。
#### 建议11:Python的枚举
python3.4之前是没有枚举的,3.4之后加入的枚举:Enum。参考的是第三方模块flufl.enum。具体请谷歌。
#### 建议12:不推荐type进行类型检查
* 基于内建类型扩展的用户自定义类型,tyoe函数并不能准确的返回结果。(有待自我测试,书上这么说的)
* 古典类中,所有的实例type值是相等的<type 'instance'>。这与我们想要的检查类型是大相径庭。
***所以,尽可能的不要使用type检查类型,使用isintance方法检查:***
In [3]: isinstance('a', str)
Out[3]: True
In [4]: isinstance((1, 2), (str, tuple)) # 满足其中的一条就会返回true
Out[4]: True
#### 建议13:涉及除法转换为浮点数计算
因为c语言中有类型的强制转换,c语言作为静态语言,如果不进行类型的强制转换问题不大。但是python是动态类型,在定义变量的时候没有申明变量的类型。
推荐的做法是:涉及到除法运算尽量将操作数转换为浮点数在运算。
#### 建议14:避免使用eval()方法,存在安全漏洞
直接使用eval函数给程序的调试带来一定的困难。所以,需要使用eval函数的地方,用ast.literal_eval方法代替。
#### 建议15:使用enumerate获取序列迭代的索引和值
In [14]: m = ['a', 'b', 'c', 'd', 'e']
In [15]: enumerate(m)
Out[15]: <enumerate at 0x2d721421dc8>
In [16]: for x, y in enumerate(m):
...: print (x , ":" ,y )
...:
0 : a
1 : b
2 : c
3 : d
4 : e
这个方法具有一定的惰性。每次仅在需要的时候产生一个(index,item)。其本质是一迭代器,可以使用'__next__()'方法迭代下一个元素,这是python3中的,或者是next(迭代器名称)。
但是在序列是字典的时候,这个方法就不适合。因为迭代出来的是索引和值。对于字典还是起先的使用字典的iteritems方法更合适:
In [33]: r = {'a': 'aa', 'b':'bb', 'c': 'cc'}
In [34]: t = enumerate(r)
In [35]: t
Out[35]: <enumerate at 0x2d7214215e8>
In [36]: for x, y in enumerate(t):
...: print(x, y)
...:
0 (0, 'a')
1 (1, 'b')
2 (2, 'c')
---------------------------- 这是分割线
In [1]: m = ['a', 'b', 'c', 'd']
In [2]: n = enumerate(m)
In [3]: n.__next__()
Out[3]: (0, 'a')
In [4]: n.__next__()
Out[4]: (1, 'b')
In [5]: n.__next__()
Out[5]: (2, 'c')
In [6]: n.__next__()
Out[6]: (3, 'd')
------------------ 这是分割线
In [9]: next(n)
Out[9]: (0, 'a')
In [10]: next(n)
Out[10]: (1, 'b')
下面是方法更为合适:
In [37]: r
Out[37]: {'a': 'aa', 'b': 'bb', 'c': 'cc'}
In [38]: for x, y in r.items():
...: print(x, y)
...:
a aa
b bb
c cc
#### 建议16:分清 == 和 is 适用的场景
is是检查对象标识符是否一致,也就是比较二个对象是否拥有同一块内存,```并不适合判断二个字符串是否相等```, x is y 即 id(x)=id(y);
== 是判断对象的值是否相等,实际调用的是内部的‘__eq__’方法,a == b 即a.__eq__(b)。
所以is不是能被重载的, == 是可以被重载的。
如果 x is y为True,那么x == y 也是true,反之就不会成立。
In [1]: a = 'hello'
In [2]: b = 'hello'
In [3]: a == b
Out[3]: True
In [4]: a is b
Out[4]: True
In [7]: d = ''.join(['s', 't', 'r', 'i', 'n', 'g'])
In [8]: c = 'string'
In [9]: d = ''.join(['s', 't', 'r', 'i', 'n', 'g'])
In [10]: c == d
Out[10]: True
In [11]: c is d
Out[11]: False
```注意:```
In [12]: e = 'hello world, i am chen, how are you, man!'
In [13]: d = 'hello world, i am chen, how are you, man!'
In [14]: e == d
Out[14]: True
In [15]: e is d
Out[15]: False
> 以上实例,e和d是相同的字符串,但是使用is,得出的是false。相比于上面的a和b字符串,确实不同的结果。这是因为python 的```字符串驻留机制```决定的。对于较小的字符串,为了提高系统性能会保留其值的一个副本,当创建新的字符串时直接指向该副本。但是对于长字符串,并不会驻留,python内存中各自创建对象来保存这2个长字符串,因此才会相同的内容但是对象标识符不同。
>
#### 建议17:为了兼容性,尽可能使用Unicode
Unicode是万国码。
decode方法是将其他的编码对应的字符串解码为Unicode,encode是将Unicode编码格式转换为另一种编码格式。
{% asset_img 编码解码示意图.png %}
#### 建议18:构建合理的包层次管理module
包和普通目录的区别是:包中包含了init文件。
有时可能因为不同平台间的文件的命名规则不同,python解释器并不同正确的判断模块在对应的平台该如何导入,它仅仅是执行了init文件,```此时就需要修改init文件控制模块的导入。
在init文件中,定影‘all’变量,控制需要导入的子包或者模块。
all = [‘Subpackage1’, ‘Subpackage2’, ……]
在通过dir()方法验证哪些目录是可以被导入的。
- 合理组织代码,便于维护和使用。
- 有效的避免命名空间的冲突。
基础语法
python常见的数据类型是数字,字符串,列表,字典,集合,元组等,常见的语法是条件,循环,列表解析,函数等。组合起来是python的基本要素。
建议19:有节制的使用from…import语句
建议56:理解名字查找机制
python变量的作用域
局部作用域:
全局作用域
嵌套作用域
内置作用域
建议58:理解MRO与多继承
在继承中,古典类和新式类采取的MRO(方法解析顺序)的不同,就会导致继承的顺序不一样。
- 古典类中,MRO 搜索采用的是
需要的属性或者方法的时候停止搜索。继承是在上一层级中从左到右依次,对每一个节点查找,此节点中没有则在此节点的父级节点上查出。
1
2
3
4
5
> * 新式类中,采用的是广度优先搜索,首先遍历每一个层级是否有需要的方法或者属性。一个个层级向上查找。 实际这是C3 MRO搜索方法。新式类中可以通过‘__mro__’属性查找。
MRO虽然叫方法解析顺序,但是对于类中的数据属性,也是适用的。如果继承是没有找到需要的方法或者属性,python解释器会抛出异常。
```注意:
在多继承的关系中,要避免出现菱形的继承关系。如下: