我是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():
print 'f called'
@countcalls
是否等同于创建一个countcalls
对象并将下面的函数传递给它的__init__
方法?在
__call__
接受三个参数。self
就上面的问题而言是可以的。另外两个论点到底是什么:*args, **kwargs
它们实现了什么?
我怎样才能在装饰方面做得更好?
相当于:
f = countcalls(f)
换句话说:是的,我们正在创建一个
countcalls
对象并将f
传递给它的构造函数。这些是函数参数。在您的例子中,
f
不带参数,但假设f
是这样调用的:f(3, 4, keyword=5)
那么}。有关
*args
将包含3和4,**kwargs
将包含键/值对{*args
和**kwargs
的更多信息,请参见this question。熟能生巧。
这个代码似乎有些奇怪。让我们来谈谈稍微简单一点的代码
记住
^{pr2}$是同一件事
因此,当我们使用decorator时,函数是使用
_f
属性存储的。在所以
f
是一个countcalls
实例。当您执行f(...)
时,您将调用f.__call__(...)
-这就是您为自己的实例实现()
语法的方法。所以当你调用f
时,会发生什么?在首先,使用
*args
和**kwargs
,它们在定义中将所有位置和关键字参数压缩为元组和dict,然后在调用中将序列和dict扩展为参数(有关更多信息,请参阅官方教程中的4.7.4)。这是一个局部的例子所以
def f(*args, **kwargs): return g(*args, **kwargs)
只对所有参数进行一次传递。在除此之外,您只需记录您在这个实例中的
__call__
的次数(您调用f
)的次数。在只要记住
@dec
def f(...): ...
与def f(...): ...
f = dec(f)
是一样的,只要有足够的时间,你应该可以很好地找出大多数装饰器。像所有的事情一样,练习会帮助你更快更容易地做到这一点。在有一个很容易找到的方法。在
所以,是的。在
差不多了。这相当于将结果赋给函数名,即
^{pr2}$相关问题 更多 >
编程相关推荐