python知识回顾 参考廖雪峰的python教程
1. 函数默认传参
def add_end(L=[]):
L.append('END')
return L
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']
由于L指向的是一个可变对象,每次指向的会发生改变
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
可以用None这个不变对象来实现
2. 函数可变参数与关键字参数
args是可变参数,args接收的是一个tuple;
kw是关键字参数,kw接收的是一个dict。
3. 切片器
L = list(range(100))
>>> L[10:20]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]#取从标为10 取到下标为20的前一个
L[0:10:2]
[0, 2, 4, 6, 8]#前10个数,每两个取一个:
字符串,tuple,和 list 都可以用切片器
4. 迭代
for key in d:
for value in d.values()
for k, v in d.items()
5. 列表生成式
[x * x for x in range(1, 11) if x % 2 == 0]
[m + n for m in 'ABC' for n in 'XYZ']
[k + '=' + v for k, v in d.items()]
isinstance函数可以判断一个变量是不是字符串:
lower()单词大小写转化
6. 生成器
不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator
- 第一种方法
>>> g = (x * x for x in range(10))
>>> for n in g:
print(n)
创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。
- 第二种方法 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'
>>> g = fib(6)
>>> while True:
... try:
... x = next(g)
... print('g:', x)
... except StopIteration as e:
... print('Generator return value:', e.value)
... break
这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
杨辉三角形
def triangles():
p = [1]
while True:
yield p
p = [1] + [p[i] + p[i+1] for i in range(len(p)-1)] + [1]
n = 0
results = []
for t in triangles():
results.append(t)
n = n + 1
if n == 10:
break
for t in results:
print(t)
7. 高阶函数 函数作为参数传递
- map
>>> def f(x):
... return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]
map()传入的第一个参数是f,即函数对象本身。由于结果r是一个Iterator,Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。
- reduce fn(fn(x), y)
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
把序列[1, 3, 5, 7, 9]变换成整数13579,reduce就可以派上用场
>>> from functools import reduce
>>> def fn(x, y):
... return x * 10 + y
...
>>> reduce(fn, [1, 3, 5, 7, 9])
13579
把str转换为int的函数:
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))
- filter filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]
生成一个奇数序列
# 从3开始生成序列
def _odd_iter():
n = 1
while True:
n = n + 2
yield n
# 过滤器
def _not_divisible(n):
return lambda x: x % n > 0 #返回出来的是一个lamada的表达式,值得注意
#求序列
def primes():
yield 2
it = _odd_iter() # 初始序列
while True:
n = next(it) # 返回序列的第一个数
yield n
it = filter(_not_divisible(n), it) # 构造新序列
for n in primes():
if n < 1000:
print(n)
else:
break
- sorted 可以对list进行排序,字符串的话通过ASCII的大小比较的,由于’Z’ < ‘a’,结果,大写字母Z会排在小写字母a的前面
sorted([36, 5, -12, 9, -21], key=abs)#高阶函数,可以指定key即排序的方式
[5, 9, -12, -21, 36]
8. 函数作为返回值 闭包
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f #仅仅是一个函数
<function lazy_sum.<locals>.sum at 0x101c6ed90>
>>> f()#函数调用
25
注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用
闭包容易错的点
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
>>> f1()
9
>>> f2()
9
>>> f3()
9
你可能认为调用f1(),f2()和f3()结果应该是1,4,9
全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9, 返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs
闭包写出的计数器
def createCounter():
s = [0]
def counter():
s[0] = s[0]+1
return s[0]
return counter
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
counterB = createCounter()
if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:
print('success!')
else:
print('fail!')
9. 装饰器
import functools
def log(func):
@functools.wraps(func) #将原来的函数属性赋值
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
def now():
print('2015-3-25')
@log #装饰器 now = log(now)
def now():
print('2015-3-25')
>>> now()
call now():
2015-3-25
带参数的装饰器
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('execute') #now = log('execute')(now)
def now():
print('2015-3-25')
9. 类中常用的一些方法
- type() 查看函数类型
- isinstance(d, Husky) 判断是否是某一种类型
- dir() 获得一个对象的所有属性和方法
- hasattr(obj, ‘x’) * obj 有属性’x’吗?*
- setattr(obj, ‘y’, 19) 设置一个属性’y’
def readImage(fp):
if hasattr(fp, 'read'):
return readData(fp)
return None
我们希望从文件流fp中读取图像,我们首先要判断该fp对象是否存在read方法,如果存在,则该对象是一个流,如果不存在,则无法读取。hasattr()就派上了用场。
10. 错误处理
try:
print('try...')
r = 10 / 0
print('result:', r)
except ZeroDivisionError as e:
print('except:', e)
finally:
print('finally...')
print('END')