我在python中编写一个简单的装饰器类来计算函数调用。到目前为止,我的代码能够正确计算函数调用,即使在 with 块中也是如此。我的问题是我还想跟踪我在上下文管理器中调用装饰函数的次数(据我所知)。
以下是如何使用/测试该类:
@fcount2
def f(n):
return n+2
for n in range(5):
print f(n)
print 'f count =',f.count
def foo(n):
return n*n
with fcount2(foo) as g:
print g(1)
print g(2)
print 'g count =',g.count
print 'f count =',f.count
with fcount2(f) as g:
print g(1)
print g(2)
print 'g count =',g.count
print 'f count =',f.count
with f:
print f(1)
print g(2)
print 'g count =',g.count
print 'f count =',f.count
这是使用我的类和上面代码的预期输出:
2
3
4
5
6
f count = 5
1
4
with block count = 2
g count = 2
f count = 5
3
4
with block count = 2
g count = 2
f count = 7
3
4
with block count = 2
g count = 3
f count = 9
这是我的代码,除了'with block count'语句外,它能正确地完成所有操作:
class fcount2(object):
def __init__(self, inner_func):
self.inner_func = inner_func
self.count = 0
self.block_count =0
def __call__(self, *args, **kwargs):
self.count += 1
return self.inner_func(*args, **kwargs)
def __enter__(self):
self.block_count += 1
return self
def __exit__(self, exception_type, exception_value, tb):
print "with block count: " + str(self.block_count)
if exception_type is not None:
return False
return self
那么我做错了什么?你们可以帮忙或至少指出我正确的方向,这样我就可以理解 块足以使这个工作吗?我尝试过一些东西,包括静态属性,但似乎没什么用。我对python比较新,所以细微差别让我感到厌烦。
编辑 - 这是当前程序的输出。
2
3
4
5
6
f count = 5
1
4
with block count: 1
g count = 2
f count = 5
3
4
with block count: 1
g count = 2
f count = 7
3
4
with block count: 1
g count = 3
f count = 9
答案 0 :(得分:2)
每个with语句都会创建一个fcount2
的新实例,因此每个实例只有一个block_count
- 我没有答案,但代码中的一些新增内容将说明正在发生的事情。
class fcount2(object):
def __init__(self, inner_func):
self.inner_func = inner_func
self.count = 0
self.block_count =0
def __call__(self, *args, **kwargs):
self.count += 1
return self.inner_func(*args, **kwargs)
def __enter__(self):
print 'with block entered - id(self):', id(self)
self.block_count += 1
return self
def __exit__(self, exception_type, exception_value, tb):
print "with block exit - block count: " + str(self.block_count)
if exception_type is not None:
return False
return self
sep = '*************************\n'
@fcount2
def f(n):
return n+2
for n in range(5):
print f(n)
print 'f count =',f.count, ' | id(f):', id(f)
def foo(n):
return n*n
print sep
with fcount2(foo) as g:
print g(1), ' | id(g):', id(g)
print g(2), ' | id(g):', id(g)
print 'g count =',g.count, ' | id(g):', id(g)
print 'f count =',f.count, ' | id(f):', id(f)
print sep
with fcount2(f) as g:
print g(1), ' | id(g):', id(g)
print g(2), ' | id(g):', id(g)
print 'g count =',g.count, ' | id(g):', id(g)
print 'f count =',f.count, ' | id(f):', id(f)
print sep
with f:
print f(1), ' | id(f):', id(f)
print g(2), ' | id(g):', id(g)
print 'g count =',g.count, ' | id(g):', id(g)
print 'f count =',f.count, ' | id(f):', id(f)
>>>
2
3
4
5
6
f count = 5 | id(f): 66567888
*************************
with block entered - id(self): 66585136
1 | id(g): 66585136
4 | id(g): 66585136
with block exit - block count: 1
g count = 2 | id(g): 66585136
f count = 5 | id(f): 66567888
*************************
with block entered - id(self): 66587152
3 | id(g): 66587152
4 | id(g): 66587152
with block exit - block count: 1
g count = 2 | id(g): 66587152
f count = 7 | id(f): 66567888
*************************
with block entered - id(self): 66567888
3 | id(f): 66567888
4 | id(g): 66587152
with block exit - block count: 1
g count = 3 | id(g): 66587152
f count = 9 | id(f): 66567888
>>>
问题的解决方案可能是拥有一个跟踪fcount2
所有实例的类属性,类似于PythonDecoratorLibrary
我玩了一下并想出了一个解决方案,虽然我不确定它是你在寻找什么,它可能不是正确的解决方案,但它适用于你的例子的范围。
该类为其装饰的函数添加属性,调用在函数属性中累积,逻辑区分托管上下文中的调用,实例属性引用函数属性。
class fcount2(object):
def __init__(self, inner_func):
self.inner_func = inner_func
if not hasattr(self.inner_func, 'count'):
self.inner_func.count = 0
if not hasattr(self.inner_func, 'block_count'):
self.inner_func.block_count = 0
self.context_manager = False
def __call__(self, *args, **kwargs):
if self.context_manager:
self.inner_func.block_count += 1
else:
self.inner_func.count += 1
return self.inner_func(*args, **kwargs)
def __enter__(self):
self.context_manager = True
return self
def __exit__(self, exception_type, exception_value, tb):
if exception_type is not None:
return False
self.context_manager = False
return self
@property
def count(self):
return self.inner_func.count
@property
def block_count(self):
return self.inner_func.block_count
用法:
@fcount2
def f(n):
return n+2
for n in range(5):
print f(n),
print 'f.count =',f.count
@fcount2
def foo(n):
return n*n
print sep, 'with foo as g: ...'
with foo as g:
print g(1), g(2)
print 'foo.count =',foo.count, ' | foo.block_count:', foo.block_count
print 'f.count =',f.count, ' | f.block_count:', f.block_count
print sep, 'with f as g: ...'
with f as g:
print g(1), g(2)
print 'foo.count =',foo.count, ' | foo.block_count:', foo.block_count
print 'f.count =',f.count, ' | f.block_count:', f.block_count
>>>
2 3 4 5 6 f.count = 5
*************************
with foo as g: ...
1 4
foo.count = 0 | foo.block_count: 2
f.count = 5 | f.block_count: 0
*************************
with f as g: ...
3 4
foo.count = 0 | foo.block_count: 2
f.count = 5 | f.block_count: 2
>>>
在托管上下文中访问计数:
>>> with foo as g:
for n in [1,2,3,4,5]:
print 'g(n): {} | g.block_count: {} | foo.block_count: {}'.format(g(n), g.block_count, foo.block_count)
g(n): 1 | g.block_count: 3 | foo.block_count: 3
g(n): 4 | g.block_count: 4 | foo.block_count: 4
g(n): 9 | g.block_count: 5 | foo.block_count: 5
g(n): 16 | g.block_count: 6 | foo.block_count: 6
g(n): 25 | g.block_count: 7 | foo.block_count: 7
>>>