-
Notifications
You must be signed in to change notification settings - Fork 0
/
learnPython.txt
523 lines (401 loc) · 19.3 KB
/
learnPython.txt
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
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
第二章 运算符、表达式与内置对象
1. 实数应避免直接判断是否相等,而应比较两者之差是否在一个范围内
e.g. :
>>> (0.4-0.1) ==0.3
False
>>> abs(0.4-0.1 -0.3)<1e-6
True
2. python的变量不是存储值,而是地址或引用;解释器会根据运算符右侧表达式的value推断变量类型
3. 数字的运算过程中,有复变复,有实变实,无复无实保留整型
4. python中支持在数字中添加下划线提高数字的可读性,但不能在开头和结尾使用,也不能连续使用
>>> a=1_3
>>> b=13
>>> a-b
0
5. 标准库fractions中有对象Fraction,可用于创建分数,进行运算,将小数转换为分数
>>> from fractions import Fraction as F
>>> x=F(3,4)
>>> x
Fraction(3, 4)
>>> x-0.75
0.0
>>> x.numerator
3
>>> x.denominator
4
>>> x+y
Fraction(33, 28)
>>> x*y
Fraction(9, 28)
>>> x/y
Fraction(7, 4)
>>> x*2
Fraction(3, 2)
>>> F(3.5)
Fraction(7, 2)
6. 标准库fractions中有对象Decimal,可用于高精度运算
>>> from fractions import Decimal as D
>>> 1/9
0.1111111111111111
>>> D(1/9)
Decimal('0.111111111111111104943205418749130330979824066162109375')
>>> 1/3
0.3333333333333333
>>> D(1/3)
Decimal('0.333333333333333314829616256247390992939472198486328125')
>>> D(1/9)+D(1/3)
Decimal('0.4444444444444444197728216750')
7. Python属于强类型编程语言,Python解释器会根据赋值或运算来自动推断变量类型。Python还是一种动态类型语言,变量的类型也是可以随时变化的。
8. python中的关系运算符(小于、大于等)是分开比较的,如1<2<3 等价于 1<2 and 2<3
关系运算符支持对字符串、实数、列表、元组等比较大小
9. 集合的交、并、差、对称差分别是&、|、-、^,
>>> {1, 2, 3} | {3, 4, 5} #并集,自动去除重复元素
{1, 2, 3, 4, 5}
>>> {1, 2, 3} & {3, 4, 5} #交集
{3}
>>> {1, 2, 3} ^ {3, 4, 5} #对称差集
{1, 2, 4, 5}
>>> {1, 2, 3} - {3, 4, 5} #差集
{1, 2}
10. python的and or返回的是最后表达式的值,而非总是True 或者 False
>>> 3 and 5 #最后一个计算的表达式的值作为整个表达式的值
5
>>> 3 and 5>2
True
11. 其他进制转换为十进制:函数bin、oct、hex,而10->其他进制是:int('str',base),其中的base为2--36的整数,如int('11',2)=3;int('11',8)=9
如果base为0,则用str默认的进制进行转换,如int('0b11',0)=2
12. ord()和chr()是一对功能相反的函数,ord()用来返回单个字符的Unicode码,而chr()则用来返回Unicode编码对应的字符,
>>> chr(ord('A')+1) #Python不允许字符串和数字之间的加法操作
>>> 'B'
>>> ord('董') #这个用法仅适用于Python 3.x
>>> 33891
>>> ord('付')
>>> 20184
13. enumerate函数
enumerate()函数用来枚举可迭代对象中的元素,返回可迭代的enumerate对象,其中每个元素都是包含索引和值的元组,用list(enumerate(seq))查看结果
14. map函数
map()把一个函数func依次映射到序列或迭代器对象的每个元素上,并返回一个可迭代的map对象作为结果,map对象中每个元素是原序列中元素经过函数func处理后的结果。
>>> list(map(str, range(5))) #把列表中元素转换为字符串
>>> ['0', '1', '2', '3', '4']
>>> def add(x, y): #可以接收2个参数的函数
return x+y
>>> list(map(add, range(5), range(5,10)))
#把双参数函数映射到两个序列上
[5, 7, 9, 11, 13]
15. reduce函数
标准库functools中的函数reduce()可以将一个接收2个参数的函数以迭代累积的方式从左到右依次作用到一个序列或迭代器对象的所有元素上,并且允许指定一个初始值。
>>> from functools import reduce
>>> seq = list(range(1, 10))
>>> reduce(lambda x, y: x+y, seq)
45
>>> reduce(operator.add, map(str, seq)) #转换成字符串再累加
'123456789'
16. fliter函数
内置函数filter()将一个单参数函数作用到一个序列上,返回该序列中使得该函数返回值为True的那些元素组成的filter对象,如果指定函数为None,则返回序列中等价于True的元素
>>> seq = ['foo', 'x41', '?!', '***']
>>> def func(x):
return x.isalnum() #测试是否为字母或数字
>>> filter(func, seq) #返回filter对象
<filter object at 0x000000000305D898>
>>> list(filter(func, seq)) #把filter对象转换为列表
['foo', 'x41']
17. zip函数
zip()函数用来把多个可迭代对象中的元素压缩到一起,返回一个可迭代的zip对象,其中每个元素都是包含原来的多个可迭代对象对应位置上元素的元组,如同拉拉链一样。
>>> list(zip('abcd', [1, 2, 3])) #压缩字符串和列表
[('a', 1), ('b', 2), ('c', 3)]
>>> list(zip('123', 'abc', ',.!')) #压缩3个序列
[('1', 'a', ','), ('2', 'b', '.'), ('3', 'c', '!')]
>>> x = zip('abcd', '1234')
>>> list(x)
[('a', '1'), ('b', '2'), ('c', '3'), ('d', '4')]
第三章 python的序列结构
3.1 列表
1. 列表的sort、reverse属于原地排序,即替代原列表,而库函数sorted、reversed则不会
2. 成员测试运算符in可用于测试列表中是否包含某个元素,查询时间随着列表长度的增加而线性增加,而同样的操作对于集合而言则是常数级的
3. copy()是浅复制,即只复制了原列表各元素的引用,直接修改复制所得列表y,则原列表x也会发生变化,类似的,直接给变量取名是浅复制
而deepcopy()则是深复制,复制结果与原列表独立。这些修改体现在对列表内部的列表调用append等方法进行修改的结果,如果只是直接赋值,则不影响彼此
x=[1,2,[3,4]]
y=x[:]
print(x,y,x==y,id(x)==id(y))
>>> [1, 2, [3, 4]] [1, 2, [3, 4]] True False
y[2].append(5)
print(x,y,x==y,id(x)==id(y))
>>> [1, 2, [3, 4, 5]] [1, 2, [3, 4, 5]] True False
import copy
z= copy.deepcopy(x)
z[2].append(5)
print(x,z)
>>< [1, 2, [3, 4, 5]] [1, 9, [3, 4, 9]]
4. 列表推导式在编译器内部做了大量优化,速度很快
5. list(map(list,zip(*matrix))) 可实现矩阵转置
6. 列表切片功能强大:list[index:index]可在index处插入元素,list[::-1]可逆序列表
del list[::step] 可按照步伐长删除元素。
3.2 元组
1. 元组即使只有一个数,后面的括号也不能省略
2. 元组与列表都属于有序序列,支持双向访问、count()、index()、len()、map()、fliter()等操作
但是元组属于不可变序列,不可直接修改内部元素的value,也不能增加、删除元素。
元组的切片也只能访问元素,不能修改元素。
不可改变性也有一些好处,元组的访问更快,并且可哈希、可作为字典的key、可作为集合的值
3. 元组没有表达式,但有生成式,生成式是惰性求值,只能顺序访问每次的结果,也不支持下标访问,访问过的对象不再存在
>>> g = ((i+2)**2 for i in range(10)) #创建生成器对象
>>> g
<generator object <genexpr> at 0x0000000003095200>
>>> tuple(g) #将生成器对象转换为元组
(4, 9, 16, 25, 36, 49, 64, 81, 100, 121)
>>> list(g) #生成器对象已遍历结束,没有元素了
[]
>>> g = ((i+2)**2 for i in range(10)) #重新创建生成器对象
>>> g.__next__() #使用生成器对象的__next__()方法获取元素
4
>>> g.__next__() #获取下一个元素
9
>>> next(g) #使用函数next()获取生成器对象中的元素
16
>>> g = ((i+2)**2 for i in range(10))
>>> for item in g: #使用循环直接遍历生成器对象中的元素
print(item, end=' ')
4 9 16 25 36 49 64 81 100 121
>>> x = filter(None, range(20)) #filter对象也具有类似的特点
>>> 5 in x
True
>>> 2 in x #不可再次访问已访问过的元素
False
>>> x = map(str, range(20)) #map对象也具有类似的特点
>>> '0' in x
True
>>> '0' in x #不可再次访问已访问过的元素
False
3.3 字典
1. 字典是包含若干“键:值”元素的无序可变序列,字典中的每个元素包含用冒号分隔开的“键”和“值”两部分,表示一种映射或对应关系。
定义字典时,每个元素的“键”和“值”之间用冒号分隔,不同元素之间用逗号分隔,所有的元素放在一对大括号“{}”中。
字典中元素的“键”可以是Python中任意不可变数据,例如整数、实数、复数、字符串、元组等类型等可哈希数据,但不能使用列表、集合、字典或其他可变类型作为字典的“键”。
另外,字典中的“键”不允许重复,而“值”是可以重复的。
2. dict.setdefault(keyName, Value) 可以往dict末端添加键值对,也可以dict[keyName]=Value
3. dict默认遍历对象为key,用items()则返回键值对,values()则返回值
4. dict.update()函数可以将两个字典合并,如有相同key,则以新的键值对代替之
5. del dict[key]、dict.pop(key)删除指定元素
6. 此外,from collections import default, Collections 可以更高效地完成上述统计频次的工作
3.4 集合
1. 集合是无序、可变序列,元素不允许重复,不允许可变,所以集合的元素只能是数字、字符串、元组,不能是列表、字典、集合
2. 集合也支持集合生成式,如:
>>> a_set = set(range(8, 14)) #把range对象转换为集合
>>> a_set
{8, 9, 10, 11, 12, 13}
>>> b_set = set([0, 1, 2, 3, 0, 1, 2, 3, 7, 8]) #转换时自动去掉重复元素
>>> b_set
{0, 1, 2, 3, 7, 8}
3. 集合可通过add、update函数添加元素,update的对象是另一个集合,并自动对两个集合取并集
4. 集合的pop函数会随机删除、返回集合中的一个元素,remove、discard删除指定元素,clear清空,
5. 集合的<表示包含关系
6. 集合和字典对关键字 in 的查找速度远快于list
3.5 序列解包
1. 序列解包是python非常有特点的一个功能,如多位赋值
x, y, z= 1, 2,3
x, y, z = (1,2,3)
第四章 程序控制结构
1. 局部变量访问速度比全局变量快,如
import math
for i in range(1000):
math.sin(i)
这个速度就不如
loc = math.sin
for i in range(1000):
loc(i)
2. 把多个字符串合并在一起,要用join函数而非+
第五章 函数
1. 函数的参数是传递形参,如果传递实数,在函数内部修改值不会影响实参;如果是可变的序列结构,且在函数内部
运用序列结构自身的方法进行修改序列结构,则会影响实参
>>> def addOne(a):
print(id(a), ':', a)
a += 1
print(id(a), ':', a)
>>> v = 3
>>> id(v)
1599055008
>>> addOne(v)
1599055008 : 3
1599055040 : 4
>>> v
3
>>> id(v)
1599055008
>>> def modify(v): # 使用下标修改列表元素值
v[0] = v[0]+1
>>> a = [2]
>>> modify(a)
>>> a
[3]
1. 函数的参数
0)普通的位置参数要求实参和形参的顺序、个数相同,下介绍一些其他参数
1)默认参数
默认参数的使用可以简化函数调用,如将最常用的参数设为默认参数。默认参数的右边不能再出现没有默认值的普通参数。
多次调用函数并且不为默认参数赋值时,只会在定义时对参数进行一次解释和初始化,之后再次调用函数则会使用上一次的结果作为参数
如:
def add_end(L=[]):
L.append('END')
return L
如果对不同对象反复直接调用add_end,则列表会保留上一次结果,end累计,因此正确写法为:
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
从而避免结果的累计
还有一点,如果默认参数的值依赖某个变量,则其实际形参赋值是函数第一次初始化、定义时的赋值,再修改变量也不会影响形参、函数
2)关键参数
即通过参数名进行赋值,不必遵循顺序
3)可变长度参数
适用于参数个数未知且不定的情况,主要有 *parameter和**parameter两种形式,前者将接受的参数收集成元组,后者则需要用关键字参数的方法赋值,并收集成字典
def demo(*p):
print(p)
demo(1,2,3)
(1,2,3)
def demo(**p):
for i in p.items():
print(i)
demo(x=1,y=2,z=3)
{x:1,y:2,z:3}
如计算任意个数的平方和,写法为 *variable_name
这样输入的数据会以元组的形式传入,同样,如果要传列表或元组进去,也加 * 即可
在传递形参时,也可以用序列解包的方法,*+序列名
def demo(a,b,c):
print(a+b+c)
seq=[1,2,3]
demo(*seq)
6
d ={1:'a',2:'b',3:'c'}
demo(*d)
abc
各个参数的位置关系是:普通的位置参数、默认参数、一个星号的可变长度参数、两个星号的可变长度参数
2. 递归函数
为了避免递归溢出,可以采取尾递归,
即在函数返回的时候,调用自身本身,并且,return语句不能包含运算表达式
如普通的阶乘计算,递归表达为:
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
采用尾递归,可以优化为如下代码
def fact(n):
return fact_iter(n, 1)
def fact_iter(num, product):
if num == 1:
return product
return fact_iter(num - 1, num * product)
3. 高级特性
1)切片
L[start:end:stepsize],取出左闭右开区间start到end的元素,start默认为0,end默认为size,步长默认为1
切片也对倒者取元素适用,
list、tuple和str都支持切片
2)迭代
python支持一切可迭代对象的迭代,不一定要下标访问,如字典
考察对象是否可迭代的方法:
from collections import Iterable
isinstance(variable_type, Iterable)
3)列表生成式
即用表达式确定列表元素,如
[x * x for x in range(1, 11)]
并且,支持两层循环,如:
[m + n for m in 'ABC' for n in 'XYZ']
甚至调用函数
[s.lower() for s in L]
并且,列表生成式也支持用if...else,如:
[x for x in range(1, 11) if x % 2 == 0]
或
[x if x % 2 == 0 else -x for x in range(1, 11)]
即,如果if写在for后,则只能带if,如果写在for前,则要加上else
4)生成器
如果列表元素可以按照某种算法推算出来,可以在循环的过程中不断推算出后续的元素
一种简单的方法是类似列表生成式,将[]改为(),如:g = (x * x for x in range(10))
可通过循环查看元素
另一种是 通过yield关键字来表明,该函数为生成器,如:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b #生成器的关键字
a, b = b, a + b
n = n + 1
return 'done'
yield关键字即告诉编译器,每次执行到yield返回,下一次从yield继续
5)迭代
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
注意,list、dic、tuple和字符串都是可迭代的,即可用for循环
但只有tuple是迭代器,即使用iter()函数,因为迭代器是惰性的,需要才计算。
4. 函数式编程
1)定义
函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量
因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用
2)高阶函数
即以函数作为参数的函数,如
def add(x, y, f):
return f(x)+f(y)
以下谈几个例子
i)map与reduce
首先是map,即把函数f作用到后面可迭代的对象,并返回一个列表L
假设f是x*x的效果,如L =map(f, [1,2,3,4,5])
其次是reduce,同样是f+iterable的形式,不过其要求f必须可接受两个参数,
因为reduce会把函数返回的结果与下一个元素继续套用函数,如
reduce(add, [1, 3, 5, 7, 9])
可对数列求和
如果将map和reduce配合起来,我们可以写一个字符串数字转换为数字的函数
from functools import reduce
DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
def str2int(s):
def fn(x, y):
return x * 10 + y
def char2num(s):
return DIGITS[s]
return reduce(fn, map(char2num, s))
ii)fliter
其格式与map类似,不过他返回的是使f返回true的元素。如:
list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
只会返回'A','B','C'
iii)sorted函数
该函数是对对象进行排序,可以通过指名key函数的方法,对对象预处理,从而得到更多的排序方法
注意,key函数是对对象的每一个元素进行映射,如
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
return t[0]
sorted(L, by_name)
即可实现依照name进行排序
3)返回函数
即返回值是函数的函数,如计算可变参数的和,但不要立即输出结果,可用如下代码:
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
像这样,在函数内部定义新函数,使得新函数能享用外部函数的参数与局部变量,
而外部函数返回的参数和局部变量都包含在内部函数里。这种结构成为闭包
4)匿名函数
借助lambda关键字定义匿名函数,如:lambda x: x*x 等价于 返回x的平方的函数
冒号前是函数的参数,可以有多个,冒号后是返回值,只能有一个
5)装饰器
在函数动态运行期间修改功能的方法,如@property表示该函数只提供对私有成员的访问,而不能修改
第六章 OOP
1. 动态添加、修改类的属性:在Python中比较特殊的是,可以动态地为自定义类和对象增加或删除成员,这一点是和很多面向对象程序设计语言不同的,也是Python动态类型特点的一种重要体现。
class Car:
price = 100000 #定义类属性
def __init__(self, c):
self.color = c #定义实例属性
car1 = Car("Red") #实例化对象
car2 = Car("Blue")
print(car1.color, Car.price) #查看实例属性和类属性的值
Car.price = 110000 #修改类属性
Car.name = 'QQ' #动态增加类属性
car1.color = "Yellow" #修改实例属性
print(car2.color, Car.price, Car.name)
print(car1.color, Car.price, Car.name)
2. python中支持类和实例分别拥有数据成员,前者称为类的数据成员D,后者称为实例的数据成员d1,d2...
实例可以访问D,也可以修改D,并且各个实例修改的D互相独立;实例可以新增、删除d1、d2,各个实例的数据成员也彼此独立
相反地,类只能访问D,不能访问d
3. python也可以动态为对象添加方法,首先把新方法写好:
def speed(self, s):
self.speed = s
然后 对象名.函数名 = types.MethodType(函数名,对象名),例:
car1.speed = types.MethodType(speed,car1)
4. 继承:子类想调用父类的函数时,父类在初始化时必须先继承object,其次使用 super(子类名,self).继承的函数名(参数)
5. 多态:子类可以重写父类的方法,实现多态性
6. 构造函数__init__与析构函数__del__,如果用户没有定义,就会使用系统默认的构造和析构函数