可调用对象
函数也是对象,函数可以调用,对象加上括号,就是对象调用自己的__call__方法,函数也是可调用对象
def foo(): print(foo.__module__,foo.__name__) foo() #等价于 foo.__call__()
都返回__main__ foo
__call__ 类中定义的方法,使实例可以像函数一样调用
格式化返回坐标的点
class Point: def __init__(self,x,y): self.x = x self.y = y def __call__(self, *args, **kwargs): return "<Point {}:{}>".format(self.x,self.y) p = Point(4,2) print(p)##返回实例的对象 print(p())##返回<Point 4:2>,调用实例,调用了__call__
加法器
class Adder: def __call__(self,*args): ret = 0 for x in args: ret += x self.ret = ret return ret adder=Adder() print(adder(1,2,3)) print(adder.ret)
斐波那契数列的实现
class Fib: def __init__(self): self.items = [0,1,1] def __call__(self,n): if n < 0: raise IndexError('Wrong Index') if n < len(self.items): return self.items[n] for i in range(n-len(self.items)+1): self.items.append(self.items[-1]+self.items[-2]) return self.items[n] fib = Fib() print(fib(5))
使用类来实现斐波那契数列较为合适,还可以缓存,检索
上下文管理
文件IO操作可以对文件对象使用上下文管理,使用with...as语法
对类使用上下文管理:
3.5之前open一个class,返回AttributeError:__exit__
3.6之后返回AttributeError:__enter__
当一个对象同时实现了__enter__和__exit__,就属于上下文管理对象
定义__enter__,进入对象相关的上下文,如果存在,with后又有as,就会将返回值绑定到as后的变量上
__exit__,退出于此对象相关的上下文,exit里加关闭文件之类的操作
进出with,打开调enter,结束调exit,
import time class Point: def __init__(self): print('init') def __enter__(self): print("enter") return 100 def __exit__(self, exc_type, exc_val, exc_tb): print('exit') with Point() as f: print('-'*30) print(f) time.sleep(5) print("_"*30) print('____________end____________')
返回中可以看到执行顺序,with后边的实例先创建,调用__init__方法,后with打开调用__enter__,
执行with中的语句,退出with时再调用__exit__,而且退出时无论上方如何执行都一定会被with清除占用的资源。
with可以开启一个上下文运行环境,在执行前做一些准备工作,执行后做一些收尾工作
with Point() as f: raise Exception('error') print('123')
通过上个实验,可以看到,即使是异常的抛出都无法阻止with执行__exit__
import sys with Point() as f: sys.exit(100) print('123') print('outer')
这个例子更极端,直接退出当前解释器,也不会阻止with执行清理
所以,上下文管理是安全的
with语句
class Point: def __init__(self): print('init') def __enter__(self): print('enter')def __exit__(self, exc_type, exc_val, exc_tb): print('exit') p = Point() with p as f: print(p==f)###返回False,as要求__enter__返回值赋给f print('~~~~~')
以上代码缺少__enter__的返回值,所以不等
class Point: def __init__(self): print('init') def __enter__(self): print('enter') return self def __exit__(self, exc_type, exc_val, exc_tb): print('exit') p = Point() with p as f: print(p==f) print('~~~~~')
__enter__方法返回值就是上下文中使用的对象,with语法会把它的返回值赋给as字句的变量
__exit__方法有三个参数,(self,exc_type,exc_value,traceback)
这三个参数都与异常有关,如果没有异常这三个参数就是None。
如果有异常,参数就有意义
exc_type表示异常类型,exc_value,表示异常的值,traceback异常追踪的信息
__exit__方法返回一个等效的True的值,则压制异常,否则抛出异常
class Point: def __init__(self): print('init') def __enter__(self): print('enter') return self def __exit__(self, exc_type, exc_val, exc_tb): print(exc_type)##类型,此处返回Exception print(exc_val)##此处返回with中返回的异常值,"what's wrong" print(exc_tb)##返回异常追踪<traceback object at 地址> print('exit') return True###为等效True都会压制异常 p = Point() with p as f: raise Exception("what's wrong") print('do sth') print('outer')
enter不可加参数
exit中traceback
exit 的return为等效bool值True时,可以压制异常,为False时不压制
资源申请和资源释放
安全性
装饰器,类成为装饰器
inspcct看类的签名
多个装饰器的顺序会有影响,???留问题了
wrapper复习
应用场景,增强功能类似装饰器,
资源管理,链接管理’
权限验证
contextmanager