没有多少人知道这个特性,但是Python的函数(和方法)可以有属性。见:

>>> def foo(x):
...     pass
...     
>>> foo.score = 10
>>> dir(foo)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__getattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name', 'score']
>>> foo.score
10
>>> foo.score += 1
>>> foo.score
11

在Python中,这个特性可能的用途和滥用是什么?我所知道的一个很好的用法是PLY使用docstring将语法规则与方法关联起来。但是自定义属性呢?有充分的理由使用它们吗?


当前回答

有时我使用函数的属性来缓存已经计算出来的值。您还可以使用泛型装饰器来泛化这种方法。要注意并发问题和此类函数的副作用!

其他回答

我总是假设这是可能的唯一原因是有一个逻辑的地方来放置文档字符串或其他类似的东西。我知道如果我把它用于任何生产代码,它会让大多数阅读它的人感到困惑。

你可以用JavaScript的方式做对象…这没有任何意义,但它是有效的;)

>>> def FakeObject():
...   def test():
...     print "foo"
...   FakeObject.test = test
...   return FakeObject
>>> x = FakeObject()
>>> x.test()
foo

我已经创建了这个helper decorator来轻松设置函数属性:

def with_attrs(**func_attrs):
    """Set attributes in the decorated function, at definition time.
    Only accepts keyword arguments.
    E.g.:
        @with_attrs(counter=0, something='boing')
        def count_it():
            count_it.counter += 1
        print count_it.counter
        print count_it.something
        # Out:
        # >>> 0
        # >>> 'boing'
    """
    def attr_decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            return fn(*args, **kwargs)

        for attr, value in func_attrs.iteritems():
            setattr(wrapper, attr, value)

        return wrapper

    return attr_decorator

用例是创建工厂集合,并查询它们可以在函数元级别上创建的数据类型。 例如(非常愚蠢的一个):

@with_attrs(datatype=list)
def factory1():
    return [1, 2, 3]

@with_attrs(datatype=SomeClass)
def factory2():
    return SomeClass()

factories = [factory1, factory2]

def create(datatype):
    for f in factories:
        if f.datatype == datatype:
            return f()
    return None

我很少使用它们,但它们非常方便:

def log(msg):
   log.logfile.write(msg)

现在我可以在整个模块中使用log,并通过设置log.logfile来重定向输出。有很多很多其他的方法来实现这一点,但这个方法是轻量级的,非常简单。虽然我第一次这么做时感觉很奇怪,但我现在相信这比使用全局日志文件变量好得多。

有时我使用函数的属性来缓存已经计算出来的值。您还可以使用泛型装饰器来泛化这种方法。要注意并发问题和此类函数的副作用!