我正在从thecodeship的精彩教程中学习一些关于装饰器的知识,但我发现自己对一个例子感到困惑。
首先给出一个简单的例子,然后解释装饰器是什么。
def p_decorate(func):
def func_wrapper(name):
return "<p>{0}</p>".format(func(name))
return func_wrapper
def get_text(name):
return "lorem ipsum, {0} dolor sit amet".format(name)
my_get_text = p_decorate(get_text)
print my_get_text("John")
现在这对我有意义。装饰器只是函数的包装器。在这个家伙的解释中,他说装饰器是一个函数,它将另一个函数作为参数,生成一个新函数,并返回生成的函数以供在任何地方使用。
现在相当于上面的代码是:
def p_decorate(func):
def func_wrapper(name):
return "<p>{0}</p>".format(func(name))
return func_wrapper
@p_decorate
def get_text(name):
return "lorem ipsum, {0} dolor sit amet".format(name)
print get_text("John")
我相信我理解在没有参数的情况下装饰器的初始化方式。如果我错了,请纠正我。
get_text
,因为p_decorate
返回函数func_wrapper
,我们最终会得到真实的语句get_text = func_wrapper
。对我来说重要的是第一个等效的代码块,因为我看到并理解了装饰器的行为。
令我困惑的是以下代码:
def tags(tag_name):
def tags_decorator(func):
def func_wrapper(name):
return "<{0}>{1}</{0}>".format(tag_name, func(name))
return func_wrapper
return tags_decorator
@tags("p")
def get_text(name):
return "Hello "+name
print get_text("John")
如果我错了,请再次纠正我,但这是我的理解。
tags_decorator
假设将传入的参数是函数
被装饰,get_text
。对于我来说,看看“非装饰器”形式的等效代码块可能会有所帮助,但我似乎无法理解那些看起来像什么的东西。我也不理解为什么tags_decorator
和func_wrapper
都被返回。如果装饰器只需要返回1个函数来包装get_text
,则返回两个不同函数的目的是什么。
作为旁注,它实际上归结为以下几点。
答案 0 :(得分:7)
在限制范围内,执行@
后的所有内容生成装饰器。在您的第一个示例中,@
后面的内容只是一个名称:
@p_decorate
所以Python查找p_decorate
并用装饰函数作为参数调用它:
get_text = p_decorate(get_text)
(过度简化了一点,get_text
最初没有绑定到原始函数,但你已经得到了要点。
在你的第二个例子中,装饰器表达式涉及更多,它包括一个调用:
@tags("p")
因此Python使用tags("p")
来查找装饰器。最后这是执行的内容:
get_text = tags("p")(get_text)
tags("p")
的输出就是这里的装饰者!我将tags
函数本身称为装饰器 factory ,它在调用时生成装饰器。当您致电tags()
时,会返回tags_decorator()
。这是真正的装饰器。
您可以改为移除装饰器功能并对"p"
值进行硬编码并直接使用:
def tags_decorator_p(func):
def func_wrapper(name):
return "<{0}>{1}</{0}>".format("p", func(name))
return func_wrapper
@tags_decorator_p
def get_text(name):
# ...
但是你必须为tags()
的参数的每个可能值创建单独的装饰器。这是装饰工厂的价值,您可以向装饰器添加参数并更改功能的装饰方式。
装饰者工厂可以使用任意数量的参数;它只是你调用生成装饰器的函数。装饰器本身只能接受一个参数,即装饰功能。
我在答案开始时说在限制之内是有原因的; @
后面的表达式的语法只允许带点名称(foo.bar.baz
,因此属性访问)和调用((arg1, arg2, keyword=arg3)
)。请参阅reference documentation。原PEP 318个州:
装饰器语句受限于它可以接受的内容 - 任意表达式都不起作用。 Guido更喜欢这种,因为有一种直觉[17]。