无法理解这个python d

2024-04-25 11:47:13 发布

您现在位置:Python中文网/ 问答频道 /正文

我是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

我的怀疑:

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

    @countcallsdef f(): print 'f called'

@countcalls是否等同于创建一个countcalls对象并将下面的函数传递给它的__init__方法?在

  1. __call__接受三个参数。self就上面的问题而言是可以的。另外两个论点到底是什么:*args, **kwargs它们实现了什么?

  2. 我怎样才能在装饰方面做得更好?


Tags: oftheinstancesselfnumberdefargsfunction
3条回答
  1. 相当于:

    f = countcalls(f)

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

  2. 这些是函数参数。在您的例子中,f不带参数,但假设f是这样调用的:

    f(3, 4, keyword=5)

    那么*args将包含3和4,**kwargs将包含键/值对{}。有关*args**kwargs的更多信息,请参见this question

  3. 熟能生巧。

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

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

记住

^{pr2}$

是同一件事

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

因此,当我们使用decorator时,函数是使用_f属性存储的。在

所以f是一个countcalls实例。当您执行f(...)时,您将调用f.__call__(...)-这就是您为自己的实例实现()语法的方法。所以当你调用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 f(*args, **kwargs): return g(*args, **kwargs)只对所有参数进行一次传递。在

除此之外,您只需记录您在这个实例中的__call__的次数(您调用f)的次数。在

只要记住@decdef f(...): ...def f(...): ...f = dec(f)是一样的,只要有足够的时间,你应该可以很好地找出大多数装饰器。像所有的事情一样,练习会帮助你更快更容易地做到这一点。在

When we prefix the decorator to a function, does that mean that we are creating an object of the decorator class right there?

有一个很容易找到的方法。在

>>> @countcalls
... def f(): pass
>>> f
<a.countcalls object at 0x3175310>
>>> isinstance(f, countcalls)
True

所以,是的。在

Is @countcalls equivalent to creating a countcalls object and passing the function below to its init method?

差不多了。这相当于将结果赋给函数名,即

^{pr2}$

How can I get better at decorators?

  1. 练习
  2. 阅读使用它们的其他人的代码
  3. 研究相关政治公众人物

相关问题 更多 >