一些概念
函数是一等对象
拿其他函数作为参数或者返回值的函数叫作高阶函数
闭包和自由变量
整个空间叫闭包。
内部函数中访问的外部函数的局部变量叫作自由变量。
*args和**kwargs
@语法糖
装饰器的4种套路
否否
是否
以上两种只是在函数的定义时加了一些小动作。
否是
是是
真正的装饰器是inner_dec(f)
针对装饰器的配置函数写在它的外面。
针对被装饰函数的包装函数,加在inner_dec()的内层,是wrapper()
总结
三层def中,只有中间的装饰器函数是必须的,外层的是配置函数,内层的是包装函数。
实战
例子一
否否类型。
tasks = []
def task(f):
global tasks
tasks.append(f)
setattr(f, "name", f.__name__)
return f
@task
def play1():
return "playing1..."
@task
def play2():
return "playing2..."
def action():
for task in tasks:
print(task.__name__, ": ", task())
if __name__ == '__main__':
action()
输出结果:
play1 : playing1...
play2 : playing2...
解读:
@task会在task1()和task2()定义时起作用,将他们添加到了tasks列表中。
在action()函数中会遍历tasks列表,将里面的task取出并调用。
例子二
是否类型。
tasks = []
def task(name=''):
if callable(name):
return task()(name)
def _task(f):
global tasks
tasks.append(f)
if name:
setattr(f, 'name', name)
else:
setattr(f, "name", f.__name__)
return f
return _task
@task
def play1():
return "playing1..."
@task("自定义2")
def play2():
return "playing2..."
def action():
for t in tasks:
print(t.name, ": ", t())
if __name__ == '__main__':
action()
这里可以学到在函数内部判断参数的类型。
例子三
from functools import partial
def complex_job(x, y, z):
print(x, y, z)
def simplify(f, x, y):
def dec(z):
return f(x, y, z)
return dec
simplified_job = simplify(complex_job, 1, 2)
simplified_job(3)
simplified_job2 = partial(complex_job, y=2, z=3)
simplified_job2(1)
这里是介绍一下functools库中的partial。
下面使用partial来写自己的my_wraps()
from functools import partial
tasks = []
def task(name=''):
if callable(name):
return task()(name)
def _task(f):
global tasks
tasks.append(f)
if name:
setattr(f, 'name', name)
else:
setattr(f, "name", f.__name__)
return f
return _task
def count(f):
counter = 0
# 两个装饰器可以互相替代
# @wraps(f)
@my_wraps(f)
def wrapper(*args, **kwargs):
nonlocal counter
counter += 1
return f(*args, **kwargs) + ' ' + str(counter)
# update_wrapper(wrapper, f)
return wrapper
def update_wrapper(wrapper, f):
setattr(wrapper, '__name__', f.__name__)
setattr(wrapper, '__doc__', f.__doc__)
return wrapper
def my_wraps(f):
return partial(update_wrapper, f=f)
@task
@count
def play1():
return "playing1..."
@task("自定义2")
@count
def play2():
return "playing2..."
def action():
for t in tasks:
print(t.name, ": ", t())
if __name__ == '__main__':
action()
参考资料
建议,直接看视频,比我讲得清楚 QAQ
https://www.bilibili.com/video/BV1Ra4y147oH
https://www.bilibili.com/video/BV1Wa4y1x7Kk