装饰器是一个可以接收一个callback作为参数并且返回一个callback引用的函数
闭包是一个返回函数的函数,可以存储外部函数的变量。python3用nonlocal关键字修改外部变量,python2用字典可以修改。两者都可以提高代码复用性。
闭包
一个简单的闭包,line函数存储了外部函数a,b变量。闭包的功能可以和一个简单类相同,因为可以存储变量。
def line_conf(a, b):
def line(x):
return a*x + b
return line
line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5))
print(line2(5))
修改外部函数的变量 用nonlocal python3。
def counter(start=0):
def incr():
nonlocal start
start += 1
return start
return incr
c1 = counter(5)
print(c1())
print(c1())
装饰器
装饰器一个隐含的特点,会自动执行装饰器函数,带参数的装饰器会执行到第二层装饰器函数。
下面展示了常用的函数装饰器的使用:
import functools
def decorated1(func): # 在函数前加日志
print("log start")
return func
def decorated2(func):
@functools.wraps(func) # 得到传进来的参数进行判断处理
def inner(*args, **kwargs):
print("log start")
return func(*args, **kwargs)
return inner
def decorated3(foo, bar="bar"): # 传参数给装饰器做具体处理
def actual_inner(func):
@functools.wraps(func)
def inner(*args, **kwargs):
print("log start", foo, bar)
return func(*args, **kwargs)
return inner
return actual_inner
@decorated3("foo")
def add(a, b):
"""add func doc."""
return a + b
print(add(2, 3))
带有参数的装饰器decorated3的执行过程是:
@decorated3("foo") # 括号操作执行这个变成
@actual_inner 这样的装饰器
def add(a, b):
pass
注意,即使不调用add方法actual_inner也会执行,只是inner要add方法调用罢了,理解下面的程序,URL_FUNC_DICT的数据什么时候产生。
装饰器demo.png
装饰器一般内部函数写return,多个装饰器从里向外执行。装饰器有基于闭包的特点,保存外部变量。
def foo(fun):
print("foo init")
l = []
s = "sss"
def inner():
l.append(23)
# nonlocal s
s = "yyyy"
print("inner fun")
print("l:{}, s:{}".format(l, s))
return inner
@foo
def bar():
print("bar fun")
bar()
bar()
装饰器也可以将一个函数装饰返回为一个类,你可能需要重写cal方法,下面是一个例子
class Task(object):
def __call__(self, *args, **kwargs):
return self.run(*args, **kwargs)
def run(self, *args, **kwargs):
raise NotImplementedError('NotImplementedError')
def identify(self):
return "I am a task"
def task(func):
class SubTask(Task):
def run(self, *args, **kwargs):
return func()
return SubTask()
@task
def foo():
print("1 + 1 = ", 2)
return 2
res = foo()