无法理解此python修饰符

无法理解此python修饰符,python,decorator,Python,Decorator,我不熟悉python装饰程序。我通过简单的例子理解了基本概念。但当我试着读这本更实用的装饰书时,我感到迷失了方向。下面是代码,后面是我的问题: class countcalls(object): "Decorator that keeps track of the number of times a function is called." __instances = {} def __init__(self, f): self.__f = f se

我不熟悉python装饰程序。我通过简单的例子理解了基本概念。但当我试着读这本更实用的装饰书时,我感到迷失了方向。下面是代码,后面是我的问题:

class countcalls(object):
   "Decorator that keeps track of the number of times a function is called."

   __instances = {}

   def __init__(self, f):
      self.__f = f
      self.__numcalls = 0
      countcalls.__instances[f] = self

   def __call__(self, *args, **kwargs):
      self.__numcalls += 1
      return self.__f(*args, **kwargs)

   def count(self):
      "Return the number of times the function f was called."
      return countcalls.__instances[self.__f].__numcalls

@countcalls
def f():
   print 'f called'

f()
f()
f()
print f.count() # prints 3
我的疑问是:

  • 当我们将decorator作为函数的前缀时,这是否意味着我们正在创建decorator类的对象?在我们的案例中,当它说:

    @countcalls
    def():
    打印“f调用”

  • @countcalls
    是否等同于创建一个
    countcalls
    对象,并将下面的函数传递给它的
    \uuuu init\uuu
    方法

  • \uuuu调用\uuuu
    包含三个参数<代码>自我可以回答上述问题。另外两个参数是什么:
    *args,**kwargs
    ,它们实现了什么

  • 我怎样才能在装饰方面做得更好

  • 是的,但需要注意的是,它还将该对象绑定到def中给定的名称

  • 阅读他们,阅读例子,玩一些

  • 当我们将decorator作为函数的前缀时,这是否意味着我们正在创建decorator类的对象

    有一个很容易找到的方法

    >>> @countcalls
    ... def f(): pass
    >>> f
    <a.countcalls object at 0x3175310>
    >>> isinstance(f, countcalls)
    True
    
    我怎样才能在装饰方面做得更好

  • 实践
  • 阅读其他人使用他们的代码
  • 研究相关的政治公众人物
  • 它相当于以下内容:

    f=countcalls(f)

    换句话说:是的,我们正在创建一个
    countcalls
    对象,并将
    f
    传递给它的构造函数

  • 这些是函数参数。在您的例子中,
    f
    不接受任何参数,但假设
    f
    的调用方式如下:

    f(3,4,关键字=5)

    然后,
    *args
    将包含3和4,而
    **kwargs
    将包含键/值对
    关键字=5
    。有关
    *args
    **kwargs
    的更多信息,请参阅

  • 熟能生巧


  • 这段代码似乎有些奇怪。让我们来谈谈稍微简单一点的代码

    class countcalls(object):
    
        def __init__(self, f):
            self._f = f
            self._numcalls = 0
    
        def __call__(self, *args, **kwargs):
            self._numcalls += 1
            return self._f(*args, **kwargs)
    
        def count(self):
            return self._numcalls
    
    @countcalls
    def f():
        print 'f called'
    
    f()
    f()
    f()
    print f.count() 
    
    # output:
    #   f called
    #   f called
    #   f called
    #   3
    
    记得吗

    @countcalls
    def f():
        print 'f called'
    
    是同一件事吗

    def f():
        print 'f called'
    f = countcalls(f)
    
    因此,当我们使用decorator时,函数是使用
    \u f
    属性存储的

    因此
    f
    是一个
    countcalls
    实例。当您执行
    f(…)
    时,您将调用
    f.\uu调用
    -这就是您为自己的实例实现
    ()
    语法的方式。那么,当您调用
    f
    时,会发生什么

        def __call__(self, *args, **kwargs):
            self._numcalls += 1
            return self._f(*args, **kwargs)
    
    首先,使用
    *args
    **kwargs
    ,在定义中将所有位置参数和关键字参数压缩为元组和dict,然后在调用中将序列和dict扩展为参数(有关详细信息,请参阅官方教程中的4.7.4)。下面是一个局部示例

    >>> def f(*args): print args
    ... 
    >>> f(1, 2)
    (1, 2)
    >>> f()
    ()
    >>> def add(a, b): return a + b
    ... 
    >>> add(*[4, 3])
    7
    >>> add(**{'b': 5, 'a': 9})
    14
    
    因此
    def(*args,**kwargs):返回g(*args,**kwargs)
    只对所有参数进行传递

    除此之外,您只需记录您在本例中使用了多少次
    \uuuuuuuuuuuuuuuuuuuuuuuuu
    (您调用了多少次
    f


    只要记住
    @dec
    def(…):…
    def(…):…
    f=dec(f)
    是一样的,如果有足够的时间,你应该能够很好地理解大多数装饰程序。像所有事情一样,实践将帮助您更快、更容易地完成这项工作。

    我最喜欢的一项:快速样式指南,不要对私有变量使用双下划线,只使用一个。@ChinmayKanchi:双下划线在Python中有特殊意义。为什么希望函数的行为根据调用的次数而改变?如果您想要状态,使用对象不是更好吗?不过,按照惯例,只能使用一个下划线来声明私有变量。只有当您不希望子类继承属性或使用特殊方法(
    \uuu eq\uu
    等)时,才应使用双下划线。还有一个问题:
    self.\uu f=f
    self.f=f
    有何不同?我知道
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。这并不意味着它们是私人的,只是拼写有点不同。这个特性通常不是很有用,而且会使代码更难使用,所以我们很多人都避免使用它。对不起,我还有一个疑问。假设我们使用函数作为装饰器,而不是类。然后它接受它正在装饰的函数的对象,对吗?现在,如果它是一个对象,我应该能够访问它的变量、属性等。这是否意味着我可以从decorator函数访问要修饰的函数中声明的变量?在这两种情况下,decorator都接收函数对象。您可以访问函数的属性,但不能以任何有意义的方式访问函数中的变量。您可以在较低的级别访问参数、默认值和代码,但不能访问任何通常有用的内容。请记住,在调用函数之前,这些变量不会引用对象,而在获取对象时也不会调用函数。
    
    >>> def f(*args): print args
    ... 
    >>> f(1, 2)
    (1, 2)
    >>> f()
    ()
    >>> def add(a, b): return a + b
    ... 
    >>> add(*[4, 3])
    7
    >>> add(**{'b': 5, 'a': 9})
    14