咱们知道函数是可以当作装饰器, 他应用的是 闭包函数特性, 实际类只要符合闭包的特性也可以当作装饰器。
实现装饰器两种方式:
- 函数实现:使用闭包;
- 类实现;
学习之前先看一下__call__
魔法方法:
class Person():
def __init__(self,name):
self.name=name
p=Person('小静')
p() #直接调用实例对象
为了符合装饰器特征,直接调用实例对象会报错:
Traceback (most recent call last):
File "C:/workspace/pythonTest/pythonDemo/call.py", line 6, in <module>
p() #
TypeError: 'Person' object is not callable
报错结果是说Person对象不是可调用对象(callable),python中一切皆对象,函数也是对象,
关于可调用对象,我们平时自定义的函数、内置函数和类都属于可调用对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable
就是说__call__()
方法能够让类的实例对象,像函数一样被调用
看一下__call__
的实现:
一个特殊的魔术方法可以让类的实例的行为表现的像函数一样,你可以调用他们,将一个函数当做一个参数传到另外一个函数中等等。这是一个非常强大的特性让Python编程更加舒适甜美。 __call__(self, [args...])
允许一个类的实例像函数一样被调用。实质上说,这意味着 x() 与 x.call() 是相同的。注意 call 参数可变。这意味着你可以定义 __call__
为其他你想要的函数,无论有多少个参数。
__call__
在那些类的实例经常改变状态的时候会非常有效。相当于重载括号运算符;
再加入__call_
方法后看一下:
class Person():
def __init__(self,name):
self.name=name
def __call__(self):
print(self.name)
p=Person('小静')
p() #直接调用实例对象
此时执行结果正确;
再看一个例子分析一下:
class Person():
def __init__(self,func):
print(" init 方法进行初始化fun")
self.__func=func
def __call__(self):
print("开始调用实例方法 fun")
self.__func()
@Person
def fun():
print("fun 方法执行")
fun()
执行结果如下:
init 方法进行初始化
开始执行 实例方法 fun
fun 方法执行
分析过程:
- @Person 相当于
fun=Person(fun)
; Person(fun)
相当于实例化, 只是他传递的比较特殊是个方法的引用,- 首先走的是 init 方法 初始化 , 打印了 init 方法进行初始化 ,
- 然后把方法fun 的引用交给了私有属性 __func
- 实例化完成以后 把Person(fun) 实例化对象把指针传递给 fun, fun指向实例化对象
- 当执行
fun()
的时候,就相当于 前面我们介绍的第一部分的内容,实例化方法自动调用了call 执行call方法里的 self.__func()
, - 这个 func的指针指向大家了解吗, fun的指针 传递给>func指针又给了>__func, 所以当我们执行self.__func 的时候 就相当于 执行 fun() 也就是被装饰的方法。