需要注意的两点:
在函数定义中定义的变量在这个函数局部范围内定义,它是任何内部函数的封闭范围,因此这个变量在这些内部函数中可用。而函数名(代码中的func)只是引用函数对象的变量。
*args 函数定义中的语法表示“将所有不匹配的位置参数作为一个元组收集,并将此元组命名为 args”,**kwargs 表示“将所有不匹配的关键字参数作为字典收集并给出字典名称kwargs"。 args 和 kwargs 只是一个约定(就像类中的 self),你可以在这个地方使用任何名称,尽管你不应该这样做。在函数调用中,* 和 ** 的语法正好相反——它分别在单个值和 key=value 对中破坏元组和字典。
现在你的代码:
def get_text(name):
#name is here in local scope and it's just a positional argument
#if you've used get_text(*args, **kwargs) you could refer to 'name' as 'args[0]'
return "lorem ipsum, {0} dolor sit amet".format(name)
def p_decorate(func):
#'func' is saved here in local scope
#here 'func' will reference 'get_text' from your example
def func_wrapper(*args, **kwargs):
#'args' and 'kwargs' are here in local scope and
#they represent all arguments passed to decorated function
#regarding your example here will be 'arg[0]="John"'
return "<p>{0}</p>".format(func(*args, **kwargs))
#in the line above in function you basicly break 'args' and 'kwargs'
#into pieces and pass them to func as separate arguments
#regarding your example you basicly call 'func("John")
#where "John" is in 'arg[0]' and considering 'func' reference
#in your example it's basicly 'get_text(name)'
return func_wrapper
#line above returns function object which will be assigned
#to some name as result of decorator call, i.e. 'my_get_text'
my_get_text = p_decorate(get_text)
#effectively it says "set 'my_get_text' to reference 'func_wrapper'
#with argument 'func'='get_text'"
print my_get_text("John")
#effectively is says "call function referenced by 'my_get_text'
#which is 'func_wrapper' with argument 'John' is equal
#to call 'func_wrapper("John")'"
# <p>Outputs lorem ipsum, John dolor sit amet</p>
使用*args 和**kwargs 使装饰器更加通用。在您的示例中,如果您知道只使用了一个参数,则可以编写如下内容:
def get_text(name):
return "lorem ipsum, {0} dolor sit amet".format(name)
def p_decorate(func):
def func_wrapper(single_argument):
return "<p>{0}</p>".format(func(single_argument))
return func_wrapper
my_get_text = p_decorate(get_text)
print my_get_text("John")
# <p>Outputs lorem ipsum, John dolor sit amet</p>
希望这会让你更清楚地理解。
关于你的问题在 cmets 中提到的装饰器语法,使用 @ 只是语法糖,所以:
def p_devorate(func):
...
@p_decorate
def get_text(name):
return "lorem ipsum, {0} dolor sit amet".format(name)
等同于:
def p_devorate(func):
...
def get_text(name):
return "lorem ipsum, {0} dolor sit amet".format(name)
get_text = p_decorate(get_text)
#redefining the name of original function to pointed to wrappe function instead