python高阶函数:__init__ , __call__ ,装饰器, hook 的应用和区别
一 :__init__()
和__call__()
的区别如下:
1. __init__()
的作用是初始化某个类的一个实例。
2. __call__()
的作用是使实例能够像函数一样被调用,同时不影响实例本身的生命周期(__call__()
不影响一个实例的构造和析构)。但是__call__()
可以用来改变实例的内部成员的值。
class Mark(object):
def __init__(self, str):
print("__init__", str)
def __call__(self, func):
print("__call__", func)
mark=Mark("str") # 声明一个实例,调用__init__传参str
mark("func") # 引用该类实例,调用__call__传参func
-----------------------------
输出结果为:
__init__str
__call__func
二: 装饰器和语法糖
装饰器版本:
def func():
print("被装饰的函数")
def add_way(func): # 1
def wrapper(): # 3
print('这是新功能') # 6
func() # 7
return wrapper # 4
func = add_way(func) # 2
func()
语法糖版本:
def add_way(func):
def wrapper():
print('这是新功能')
func()
return wrapper
@add_way
def func():
print("语法糖版本:被装饰函数")
func()
Python提供了一个 语法糖 "@" 来帮我们完成func = add_way(func)这件事情! 所以“@”和__call__组合使用时,已经完成了__call__的逻辑并返回该函数,而不是在调用函数时
class Mark:
def __init__(self, module: str = ''):
print("__init__:", module)
def __call__(self, func):
print("__call__:", func.__name__)
return func
class Api:
mark = Mark
api = Api()
class Demo:
@staticmethod
@api.mark(module='demo1')
def demo1():
print("demo1()被调用")
@staticmethod
@api.mark(module='demo2')
def demo2():
print("demo2()被调用")
d = Demo()
d.demo1()
d.demo2()
-------------------
结果:
__init__: demo1
__call__: demo1
__init__: demo2
__call__: demo2
demo1()被调用
demo2()被调用
-------------------
带参数的装饰器
# 带参数的装饰器
def post(path=''):
def decorator(func):
def wrapper(*args, **kwargs):
print('path:', path)
func(*args, **kwargs)
return wrapper
return decorator
# () 就是调用了,会decorator返回实例,会初始化,这个decorator实例可以调用,生成wrapper实例
@post('/login')
def test_login(name, pwd):
print('name:', name)
print('pwd:', pwd)
print(test_login.__name__) # 最后是个wrapper实例
def test_login2(name, pwd):
print('name:', name)
print('pwd:', pwd)
print(test_login2.__name__)
test_login('wjz', '111')
test_login2('wjz', '111')
# 看到这个代码是不是又有些疑问,内层的decorator函数的参数func是怎么传进去的?和上面一般的装饰器不大一样啊。
# 其实道理是一样的,将其@语法去除,恢复函数调用的形式一看就明白了:
# 传入装饰器的参数,并接收返回的decorator函数
# decorator = post("/login")
# 传入test_login函数
# wrapper = decorator(test_login)
# 调用装饰器函数
# wrapper("'wjz', '111'")
三 : hook函数