代码之家  ›  专栏  ›  技术社区  ›  Eli Bendersky

Python函数属性-使用和滥用[关闭]

  •  240
  • Eli Bendersky  · 技术社区  · 16 年前

    没有多少人知道这个特性,但Python的函数(和方法)可以有 attributes 请看:

    >>> 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将语法规则与方法相关联。但是自定义属性呢?有充分的理由使用它们吗?

    8 回复  |  直到 16 年前
        1
  •  135
  •   Martin v. Löwis    16 年前

    我通常使用函数属性作为注释的存储。假设我想用C#的风格编写(表示某个方法应该是web服务接口的一部分)

    class Foo(WebService):
        @webmethod
        def bar(self, arg1, arg2):
             ...
    

    然后我可以定义

    def webmethod(func):
        func.is_webmethod = True
        return func
    

    然后,当web服务调用到达时,我会查找该方法,检查底层函数是否具有is_webmethod属性(实际值无关紧要),如果该方法不存在或不打算通过web调用,则拒绝该服务。

        2
  •  112
  •   mipadi    10 年前

    我将它们用作函数的静态变量。例如,给定以下C代码:

    int fn(int i)
    {
        static f = 1;
        f += i;
        return f;
    }
    

    我可以在Python中类似地实现该函数:

    def fn(i):
        fn.f += i
        return fn.f
    fn.f = 1
    

    这肯定属于“滥用”的范畴。

        3
  •  45
  •   defnull    16 年前

    你可以用JavaScript的方式处理对象。..这没有意义,但它有效;)

    >>> def FakeObject():
    ...   def test():
    ...     print "foo"
    ...   FakeObject.test = test
    ...   return FakeObject
    >>> x = FakeObject()
    >>> x.test()
    foo
    
        4
  •  14
  •   Robert Rossney    15 年前

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

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

    现在我可以使用 log 在整个模块中,只需设置即可重定向输出 log.logfile 有很多其他方法可以实现这一点,但这个方法很轻,也很简单。虽然我第一次做的时候闻起来很奇怪,但我开始相信,它闻起来比拥有一个全球性的 logfile 变量。

        5
  •  10
  •   Kevin Little    16 年前

    函数属性可用于编写将代码和相关数据包装在一起的轻量级闭包:

    #!/usr/bin/env python
    
    SW_DELTA = 0
    SW_MARK  = 1
    SW_BASE  = 2
    
    def stopwatch():
       import time
    
       def _sw( action = SW_DELTA ):
    
          if action == SW_DELTA:
             return time.time() - _sw._time
    
          elif action == SW_MARK:
             _sw._time = time.time()
             return _sw._time
    
          elif action == SW_BASE:
             return _sw._time
    
          else:
             raise NotImplementedError
    
       _sw._time = time.time() # time of creation
    
       return _sw
    
    # test code
    sw=stopwatch()
    sw2=stopwatch()
    import os
    os.system("sleep 1")
    print sw() # defaults to "SW_DELTA"
    sw( SW_MARK )
    os.system("sleep 2")
    print sw()
    print sw2()
    

    1.00934004784

    2.00644397736

    3.01593494415

        6
  •  3
  •   unbeknown    16 年前

    我创建了这个辅助装饰器来轻松设置函数属性:

    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
    
        7
  •  2
  •   DiogoNeves    10 年前

    有时我会使用函数的属性来缓存已经计算的值。你也可以有一个通用的装饰器来推广这种方法。请注意这些函数的并发问题和副作用!

        8
  •  1
  •   Dale Reidy    16 年前

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

    推荐文章