【问题标题】:Python Functions Can Have Attributes?Python函数可以有属性吗?
【发布时间】:2014-04-13 22:48:48
【问题描述】:

我对 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(),它并没有做太多的事情,以及有关错误的详细信息。

【问题讨论】:

  • “在那一行”在哪一行?
  • 在“那一行”之前,fcount是什么?
  • 'NoneType' object has no attribute 'count' 表示fgNone,而不是属性。 Python 函数是对象;它们可以像许多其他对象类型一样具有属性。
  • 添加了一些细节来回答这些问题。
  • 这只是一种迂回的提问方式,“我如何构造一个装饰器来计算函数被调用的次数,以及如何访问该数字?”?

标签: python function attributes decorator


【解决方案1】:

我们先从f的定义说起:

@fcount
def f(n):
    return n+2

这将f 定义为对函数fcount 的调用的返回值,这里用作装饰器(前导@)。

这段代码大致相当于

def f(n):
    return n+2

f = fcount(f)

由于装饰器 - fcount - 不返回任何内容,fNone 而不是调用站点的函数

在您的情况下,fcount 应该返回一些函数并将count 属性添加到该返回的函数。有用的东西(?)可能是

def fcount(fn):
    def wrapper(n):
        wrapper.count += 1
        return fn(n)
    wrapper.count = 0
    return wrapper

编辑

正如@jonrsharpe 指出的那样,通用装饰器可以转发位置和关键字参数,方法是在签名中使用*args**kwargs 捕获它们,并在调用另一个函数时以相同的方式扩展它们。名称argskwargs 按约定使用。

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)`

【讨论】:

    【解决方案2】:

    这里的问题在于您的“装饰器功能”fcount。 Python 装饰器函数应该返回一个函数

    @decorates
    def func(...):
        ...
    

    有效:

    func = decorates(func)
    

    在你的情况下,“装饰者”fcount 只有prints,不会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
    

    【讨论】:

    • 哦,所以装饰器函数必须返回一个函数,然后它成为调用装饰器的函数的值。然后你在装饰器函数中创建另一个函数,使用 *args 和 **kwargs,来完成你想要完成的实际工作,在这种情况下,增加一个计数器?
    • 没错 - 您在装饰器函数 (fcount) 中创建了一个新函数 (func),然后(通常)使用任何参数调用参数函数 (f)已通过 (args, kwargs)。这个新函数由装饰器返回来替换原来的函数。
    • 如果我想把它放在一个类中,而不是一个独立的函数中怎么办?我是否可以将整个内容直接放在标题中,例如:class fcount2(object):
    • 我不确定你在问什么。你可以装饰类或实例方法,但装饰器仍然是一个独立的函数,而不是一个类。
    • 是的,我想我是在问类是否也可以被装饰,或者只是函数。
    【解决方案3】:

    Python 函数是一流的对象。

    他们可以有属性。

    此功能在文献中很少见,但它有其用途,例如简化的闭包。

    顺便说一句,您询问的那种计数器代码在 Pycon 2014 的有关装饰器的视频中进行了解释。

    参考

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-17
      • 2017-03-11
      • 2020-12-01
      • 1970-01-01
      • 2021-08-18
      • 2017-10-08
      • 1970-01-01
      相关资源
      最近更新 更多