我是Python的新手,我不明白函数本身看起来如何具有属性。在下面的代码中,有一个名为f的函数,稍后在代码中引用了名为f.count的函数。一个函数,即f,如何有一个.count?我收到一条错误消息:'NoneType'对象在该行上没有属性'count',所以它显然还没有该属性。我该如何赋予它属性?
def fcount(n):
print n.__name__
@fcount
def f(n):
return n+2
for n in range(5):
print n
#print f(n)
print 'f count =',f.count #THE LINE CAUSING THE ERROR MENTIONED ABOVE
@fcount
def g(n):
return n*n
print 'g count =',g.count
print g(3)
print 'g count =',g.count
编辑:添加了fcount(),它没有做任何事情,还有关于错误的详细信息。
答案 0 :(得分:5)
让我们从f
:
@fcount
def f(n):
return n+2
这将f
定义为对函数fcount
的调用的返回值,该函数在此处用作装饰器(前导@
)
此代码与
大致相同def f(n):
return n+2
f = fcount(f)
由于装饰器 - fcount
- 没有返回任何内容,f
是None
,而不是呼叫网站上的功能。
在你的情况下,fcount
应返回一些函数,并为返回的函数添加count
属性。有用的东西(?)可能是
def fcount(fn):
def wrapper(n):
wrapper.count += 1
return fn(n)
wrapper.count = 0
return wrapper
修改强>
正如@jonrsharpe指出的那样,通用装饰器可以通过在签名中使用*args
和**kwargs
捕获它们来转发位置和关键字参数,并在调用另一个函数时以相同的方式扩展它们。约定使用名称args
和kwargs
。
Python还有一个辅助函数(一个装饰器本身),它可以将信息(名称,文档字符串和签名信息)从一个函数传递到另一个函数:functools.wraps
。一个完整的例子如下:
from functools import wraps
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@decorator
def f(a, b, c=None):
"The useful f function"
pass
print f.__name__ # `f` rather than `wrapper`
print help(f) # `f(*args, **kwargs) The useful f function` rather than `wrapper(*args, **kwargs)`
答案 1 :(得分:3)
这里的问题在于你的“装饰功能”,fcount
。 Python装饰器函数应该返回一个函数:
@decorates
def func(...):
...
实际上是:
func = decorates(func)
在您的情况下,“装饰者”fcount
仅print
,并且不会return
任何内容;因此使用它将分配f = None
。
你的更普遍的问题的答案是,作为Python对象的函数,或多或少的其他东西,当然可以有属性。要实际实现你想要的东西,一个计算装饰函数调用次数的装饰器,你可以这样做:
def fcount(f):
"""Decorator function to count how many times f is called."""
def func(*args, **kwargs):
func.count += 1
return f(*args, **kwargs)
func.count = 0
return func
答案 2 :(得分:0)
他们可以拥有属性。
此功能在文献中很少见,但它有其用途,例如简化的闭包。
顺便说一句,你在问的关于装饰者的Pycon 2014视频中解释了你所询问的那种计数器代码。
<强>参考强>