无法理解此python修饰符
我不熟悉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
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
我的疑问是:
@countcalls
def():
打印“f调用”
@countcalls
是否等同于创建一个countcalls
对象,并将下面的函数传递给它的\uuuu init\uuu
方法
\uuuu调用\uuuu
包含三个参数<代码>自我可以回答上述问题。另外两个参数是什么:*args,**kwargs
,它们实现了什么>>> @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