Python的很多源码里经常会看到@abc
def f():
return 'fishc'
这样的语句。
其中紧跟在@后面的就是装饰器了。
在说装饰器之前,先来看看闭包这个东西。
小甲鱼老师在20讲时说过闭包,课后题传送门。
搞明白这段:def funOut():
def funIn():
print('宾果!你成功访问到我啦!')
return funIn()
怎么访问到 funIn?
答案是:------def funOut():
def funIn():
print('宾果!你成功访问到我啦!')
return funIn
怎么访问到 funIn?
答案是:
区别在于 funOut后面跟了一个()与两个()。
funOut,funIn是函数。
funOut(),funIn()呢,是执行函数。
如果你打印funOut你会看到一串内存地址,
funOut()你会看到这个函数执行后的返回值。
进阶的需求。
有这么一个函数。
def html_content():
return 'i love fishc.'
这个函数返回 'i love fishc.',
现在我们需要将这串字符串放在p标签, b标签与em标签下组成<p><b><em>i love fishc.</em></b></p>。
很简单嘛,def html_content():
return '<p><b><em>i love fishc.</em></b></p>'
这时我们又需要将这串字符串放在a标签下组成<a>i love fishc.</a>。
然后我们再次更改html_content函数。
这时又一个人需要把它放在div标签下。
如果我们只有几行代码还很容易修改,当代码多了之后,修改源代码并不划算。
这时候,我们就可以用装饰器来完成这个工作。
def add_em(func1):
def funin():
return '<em>{0}</em>'.format(func1())
return funin
我们定义一个叫add_em的新函数。
作用自然是添加一个em标签。
同时我们将原始html_content函数上面放上装饰器。@add_em
def html_content():
return 'i love fishc.'
print(html_content())
你觉得会出现什么?
没错就是变成这样了。我们没有修改原始代码就实现了修改原始代码的需求!
原理是什么?
@add_em 相当于 add_em(html_content)
之后我们调用 html_content时,就变成了这样。
html_content()
首先 add_em(html_content) - > funin 函数。
之后 funin + () -> funin() 执行函数。
如法炮制!
def add_em(func1):
def funin():
return '<em>{0}</em>'.format(func1())
return funin
def add_b(func1):
def funin():
return '<b>{0}</b>'.format(func1())
return funin
def add_p(func1):
def funin():
return '<p>{0}</p>'.format(func1())
return funin
@add_p
@add_b
@add_em
def html_content():
return 'i love fishc.'
print(html_content())
<p><b><em>i love fishc.</em></b></p>
不仅完成了需求,代码也很简洁,还可以重用!
参数!参数!
很多情况下函数都是有参数的,装饰器怎么带参数嘛。def html_content(arg):
return 'i love fishc.{0}'.format(arg)
只需要将内层函数加上参数就好了。def add_em(func1):
def funin(arg):
return '<em>{0}</em>'.format(func1(arg))
return funin
为什么会是这样?
上面说到 加上装饰器之后其实就是变成
add_em(html_content)(arg),
对应返回 funin (arg)
那么就是给内层函数加上参数咯,两个,三个,n个都是这样。
装饰器是否可以被执行?
def add_em(func1):
def funin(arg):
def funinin(arg):
return '<em>{0}</em>'.format(func1(arg))
return funinin
return funin
def a(arg):
return '5'
@add_em(a)
def html_content(arg):
return 'i love fishc.{0}'.format(arg)
我们知道了@add_em就是 add_em(html_content),
那@add_em(a)也就变成了add_em(a)(html_content),
那是否也会向函数一样可以加多个()表示执行?
答案是否定的,会提示语法错误。@add_em(a)(a)
@add_em(a)(a)
^
SyntaxError: invalid syntax