前言
在前面的几篇内容中,对Python的几个核心,对象协议、数字协议、比较协议、转换协议、容器协议、迭代协议以及属性协议等结合示例性代码做了扼要介绍。
本篇内容介绍函数协议(Function Protocol)以及上下文管理协议(Context Manager Protocol)。
函数协议
我们知道Python是动态语言,是由解释器来读取代码进行解释执行的,这其中就涉及函数(在类的上下文语境中,所属对象的函数中称之为方法)的解释执行,所以必须遵循一定的协议规则,否则就乱套了。
在对象中,对象可以通过提供__call__()方法来模拟函数。假设一个对象x提供了这个方法,它可以像函数一样被调用。也就是说,x(__arg1,arg2,…)实际是调用了x.__call__ (__arg1,arg2,…)。简单示例如下:
其实上述代码的最后一行还可以写成:xc.__call__('祖龙','中国'),结果完全一样。可调用对象,实际上“名称()”可以理解为是“名称.__call__()”的简写。
有许多内置类型支持函数调用。例如,类型(types)实现了调用__call__()来创建新实例。绑定(Bound)方法实现了__call__()来将self参数传递给实例方法。像functools.partial()这样的库函数也创建模拟函数的对象。
上下文管理协议
这里所谓的上下文管理协议,主要是指在一个特定范围的代码块。Python使用with语句来实现,即with语句允许在称为上下文管理器的实例的控制下执行一系列语句。一般语法如下:
实现这样的上下文协议的,需要支持如下的特定方法:
- __enter__(self)方法:在进入新的新上下文的位置调用此函数。返回值被放置在with语句一起列出的由as指定的变量中。
- __exit__(self,type,value,tb)方法:在离开上下文时调用。如果发生异常,type、value和tb包含异常类型、值和相关跟踪信息。
在执行with语句时调用__enter__()方法。此方法返回的值被放入用可选的as var说明符指定的变量中。在control-flow离开与with语句相关联的语句块时,__exit__()方法就会被调用。作为参数,__exit__()接收当前异常类型、值,并在引发异常时进行回溯。如果不处理任何错误,则将所有三个值都设置为None。__exit__()方法应该返回True或False,以指示是否处理了引发的异常。如果返回True,则清除任何挂起的异常,程序继续正常执行with块后的第一个语句。
上下文管理接口的主要用途是允许对涉及系统状态的对象进行简化的资源控制,例如打开的文件、网络连接和锁等。通过实现这个接口,当执行离开使用对象的上下文时,对象可以安全地清理资源了。
小结
本篇就写这些了,简单扼要地介绍了函数协议(直接调用对象作为函数)实现、以及上下文的协议实现。