[英]Python Decorator Class: How to correctly count function calls in a with block
I am writing a simple decorator class in python that counts function calls. 我在python中编写一个简单的装饰器类,该类对函数调用进行计数。 So far my code is able to count function calls correctly, even in a with block.
到目前为止,即使在with块中,我的代码也能够正确计数函数调用。 My issue is that I also want to keep track of how many times I call decorated functions inside of a context manager (to the best of my understanding).
我的问题是,我还想跟踪在上下文管理器中调用装饰函数的次数(据我所知)。
Here is how the class can be used/tested: 这是使用/测试类的方法:
@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
And here is the expected output using my class and the above code: 这是使用我的课程和上面的代码的预期输出:
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
Here is my code, which does everything correctly except for the 'with block count' statements: 这是我的代码,除了“ 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
So what am I doing wrong? 那我在做什么错? Can you guys help out or at least point in me in the right direction so I can understand with blocks enough to get this working?
你们可以帮忙或至少我点了正确的方向,所以我可以有足够得到这个工作块明白了吗? I have tried a handful of things including static properties but nothing seems to work.
我已经尝试了一些东西,包括静态属性,但似乎没有任何效果。 I am relatively new to python so the nuances escape me.
我是python的新手,所以细微差别使我逃脱了。
Edit- this is the output from the current program. 编辑-这是当前程序的输出。
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
Each with statement creates a new instance of fcount2
so each instance only has one block_count
- I don't have an answer but some additions to your code will illustrate what is happening. 每个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
>>>
The solution to your problem may be to have a class attribute that keeps track of all the instances of fcount2
, similar to the example in the PythonDecoratorLibrary 解决问题的方法可能是拥有一个类属性,该属性跟踪
fcount2
的所有实例,类似于PythonDecoratorLibrary中的示例
I played around a bit and came up with a solution, although I'm not sure it is what you are looking for, and it may not be the correct solution but it works for the scope of your examples. 尽管我不确定这不是您正在寻找的东西,但我花了些力气提出了一个解决方案,虽然它可能不是正确的解决方案,但它适用于示例范围。
The class adds attributes to the function it decorates, calls are accumulated in the function attributes, logic differentiates calls within a managed context , and instance properties refer to the function attributes. 该类向其装饰的函数添加属性,调用累积在函数属性中,逻辑区分托管上下文中的调用,实例属性引用函数属性。
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
Usage: 用法:
@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
>>>
Accessing the counts while in a managed context: 在托管上下文中访问计数 :
>>> 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
>>>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.