进阶语法
with ... as
上下文管理协议
with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。
已经加入对上下文管理协议支持的还有模块 threading、decimal 等。
# 操作文件
with open('file.txt') as f:
for line in f:
print(line)
匿名函数lambda
在python中使用lambda来创建匿名函数,在需要传递函数作为参数的地方使用lambda更方便。
一个lambda的例子
list(map(lambda x: x*x, [1,2,3,4,5])) #[1, 4, 9, 16, 25]
# lambdx x: x*x 等于下面的f函数 可以直接f = lambda x: x*x 赋值后调用
def f(x):
return x*x
list(map(f,[1,2,3,4,5]))
对象模拟函数 可调用接口
对象通过__call__(self [, *args [, **kwargs]])
方法模拟函数行为。如果一个对象x提供了该方法,就可以像函数一样调用它。
class DistanceFrom(object):
def __init__(self,origin):
self.origin = origin
def __call__(self,x):
return abs(x-self.origin)
nums = [1,37,42,101,13,9,-20]
newnums = sorted(nums,key=DistanceFrom(10)) #按照与10的距离排序
以上效果等同于
newnums = sorted(nums,lambda x:abs(x-10))
当然也可以直接把DistanceFrom定义成函数
使用闭包
将组成函数的语句和这些语句的执行环境打包在一起时,得到的对象称为闭包
# 计数器测试闭包效率,和使用类的时候对比
import timeit
def count(x):
def next():
nonlocal x
n = x
x -= 1
return n
return next
class count2:
def __init__(self,x):
self.x = x
def next(self):
n = self.x
self.x -= 1
return n
def test():
next = count(1000000)
while 1:
v = next()
if not v:break
def test2():
c = count2(1000000)
while 1:
v = c.next()
if not v:break
t2 = timeit.timeit(test2,number=10)
print(t2)
t = timeit.timeit(test,number=10)
print(t)
# 输出结果,闭包效率大概是正常方法的2倍
# 4.5261534636385345
# 2.468003824508422
装饰器
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
参考知乎:如何理解Python装饰器?
@wraps(func)
装饰装饰函数
,能把原函数的元信息拷贝到装饰器函数中。
上面闭包性能测试改成使用装饰器测试性能
import timeit
def timeit_test(number):
def decorated(func):
print(timeit.timeit(func,number=number))
return func
return decorated
'''略'''
'''略'''
@timeit_test(number=10)
def test():
next = count(1000000)
while 1:
v = next()
if not v:break
@timeit_test(number=10)
def test2():
c = count2(1000000)
while 1:
v = c.next()
if not v:break
# 装饰器中已运行测试方法,不需要再主动运行
yield和生成器
尽量使用生成器
range(num)
----> xrange(nums) #仅限python2,python3中range就等于之前的xrange
for k,v in dict.items()
----> for k,v in dict.iteritems()
for k in dict.keys()
----> for k in iterkeys()
yied生成斐波那契数列
def fab(max):
n ,a, b = 0, 0 ,1
while n < max:
print('before fab %d' %n)
yield a
print('after fab %d' %n)
a, b = b, a + b
n += 1
for n in fab(5):
print(n)
# 迭代就是重复运行__next__()
print('//////////////////////////////////////////')
c = fab(5)
print(c.__next__())
print(c.__next__())
print(c.__next__())
print(c.__next__())
print(c.__next__())
for循环迭代fab(5)等同于
c = fab(5)
print(c.__next__()) #运行5次
注意运行结果,每循环一次其实代码只执行到yield那一行,下一次循环直接从yield后面的代码开始执行到下一次调用yield
yield和协程
def fab():
a, b, n = 0, 1 ,0
fablist = []
while True:
number = yield fablist # 返回值不是必须的,如果number = yield,则返回的是None
while n < number:
n += 1
fablist.append(a)
a, b = b ,a + b
c = fab()
c.__next__()
for i in range(3,7):
print(c.send(i*10))
对next()的初始调用是必须的,yield语句那里协程会挂起,等待相关生成器对象c的send()方法给它发送一个值。
可以定义一个coroutine装饰器改写上述语句,这看起来和tornado
以及asyncio
很相似了。
def coroutine(func):
def start(*args, **kwargs):
c = func(*args, **kwargs)
c.__next__()
return c
return start
@coroutine
def fab():
a, b, n = 0, 1 ,0
fablist = []
while True:
number = yield fablist
while n < number:
n += 1
fablist.append(a)
a, b = b ,a + b
c = fab()
#c.__next__() #加上自定义的coroutine装饰器之后,不需要这个初始调用了
for i in range(3,7):
print(c.send(i*10))