【发布时间】:2014-12-16 09:31:57
【问题描述】:
我一直在努力更好地理解装饰器和闭包。
我正在尝试实现的装饰功能:
- 记住以前传递的值,
- 计算函数被调用的次数。
我想使用两个独立的装饰器来制作它 - 用于科学:)
所以我设法创建了这个工作代码(我使用了一些 sn-p 进行计数 - 我承认)
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
@staticmethod
def counts():
"Return a dict of {function: # of calls} for all registered functions."
return dict([(f.__name__, countcalls.__instances[f].__numcalls) for f in countcalls.__instances])
def wrapper(x):
past=[]
@countcalls
def inner(y):
print x
print inner.count()
past.append(y)
print past
return inner
def main():
foo = wrapper("some constant")
foo(5)
foo("something")
if __name__ == '__main__':
main()
输出:
some constant
1
[5]
some constant
2
[5, 'something']
现在我想将 memoize 函数更改为简洁的 Pythonic 装饰器。到目前为止,这是我得出的结论:
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
@staticmethod
def counts():
"Return a dict of {function: # of calls} for all registered functions."
return dict([(f.__name__, countcalls.__instances[f].__numcalls) for f in countcalls.__instances])
class memoize(object):
past=[]
def __init__(self, f):
past = []
self.__f = f
def __call__(self, *args, **kwargs):
self.past.append(*args)
return self.__f(*args, **kwargs)
def showPast(self):
print self.past
@memoize
@countcalls
def dosth(url):
print dosth._memoize__f.count() ## <-- this is so UGLY
dosth.showPast()
def main():
dosth("one")
dosth("two")
if __name__ == '__main__':
main()
这是输出:
1
['one']
2
['one', 'two']
如何摆脱“丑陋”的行(print dosth._memoize__f.count())?换句话说 - 我怎样才能直接调用堆叠装饰器的方法? (不向装饰器添加方法来调用其他装饰器的方法 - 这不是我的意思)
【问题讨论】:
-
你为什么要从函数中访问装饰器根本?
-
我认为在这种情况下,它是一种计算函数被调用次数并根据它修改函数行为的好方法 - 如果我想访问外部的计数属性功能的 - 我仍然需要使用 dosth._memoize__f.count()
-
如果你把计数器放在 外面 记忆器就不会了。
标签: python functional-programming decorator