[英]Need more explanation of how to implement this function counter
From The number of times a function gets called .从function 被调用的次数。
Let's say, this function is called from outside the file, and I don't have access to it.比方说,这个 function 是从文件外部调用的,我无权访问它。 I am building the function, and I just want to be able to count how many times it has been called from some other part of the program.
我正在构建 function,我只想计算从程序的其他部分调用它的次数。
I can't use the actual code that calls the function.我不能使用调用 function 的实际代码。 I do not have access to it.
我无权访问它。 I know normally I should, but for testing purposes, I am not supposed to alter the code that calls the function.
我通常知道我应该这样做,但出于测试目的,我不应该更改调用 function 的代码。 So I need to count how many times it is being called without accessing the program that calls the function.
所以我需要计算它被调用了多少次而不访问调用 function 的程序。
I have tried copy and paste into the file with the function being used like so...我尝试使用 function 复制并粘贴到文件中,就像这样使用...
def counted_calls(f):
@functools.wraps(f)
def count_wrapper(*args, **kwargs):
count_wrapper.count += 1
return f(*args, **kwargs)
count_wrapper.count = 0
return count_wrapper
def myfunction(a, b, c, d)
wrapped = counted_calls(counted_calls)
integrate.quad(wrapped, 0, 1)
print(wrapped)
****more of my code *****
return something
First I get this error: Unresolved reference 'f'
.首先我得到这个错误:
Unresolved reference 'f'
。
But I get this warning:但我收到这个警告:
Expected type 'Union[function, LowLevelCallable]', got '(args: Tuple[Any, ...], kwargs: Dict[str, Any]) -> Any' instead
Then when I run it, of course, f
is not defined.然后当我运行它时,当然
f
没有定义。
How do I get this to work so I can count how many times myfunction()
is called?如何让它工作,以便我可以计算
myfunction()
被调用的次数?
I can't call my function, another part of the program calls this function whenever it wants to.我不能调用我的 function,程序的另一部分随时调用这个 function。 I just need to track how many times it does.
我只需要跟踪它做了多少次。 I can't go put this in that part of the program and make it call the function this way.
我不能 go 把它放在程序的那一部分,并让它以这种方式调用 function。 I don't have access to it.
我无权访问它。
so like this?像这样?
def counted_calls(f):
@functools.wraps(f)
def count_wrapper(*args, **kwargs):
count_wrapper.count += 1
return f(*args, **kwargs)
count_wrapper.count = 0
return count_wrapper
wrapped = counted_calls(myfunction)
integrate.quad(wrapped, 0, 1)
print(wrapped)
def myfunction(a, b, c, d)
code code
return something
This returns the error:这将返回错误:
TypeError: myfunction() missing 3 required positional arguments:
'b', 'c', and 'd'
I tried this, but still wants more arguments or something?我试过了,但还是想要更多 arguments 什么的?
import functools
def counted_calls(f):
@functools.wraps(f)
def count_wrapper(*args, **kwargs):
count_wrapper.count += 1
return f(*args, **kwargs)
count_wrapper.count = 0
return count_wrapper
@counted_calls # <-- Apply decorator.
def myfunction(a, b, c, d):
...
return something
integrate.quad(myfunction, 0, 1)
print(myfunction.count)
TypeError: myfunction() missing 3 required positional arguments: b, c, d
So I changed it to what was recommended, however, I'm assuming b
, c
, and d
should be something specific, I just don't know what.因此,我将其更改为推荐的内容,但是,我假设
b
, c
和d
应该是特定的,我只是不知道是什么。 I tried as recommended:我按照建议尝试了:
import functools
def counted_calls(f):
@functools.wraps(f)
def count_wrapper(*args, **kwargs):
count_wrapper.count += 1
return f(*args, **kwargs)
count_wrapper.count = 0
return count_wrapper
@counted_calls # <-- Apply decorator.
def myfunction(a, b, c, d):
...
return something
integrate.quad(myfunction, 0, 1, 2, 3) # these need to be variables of some
# kind? Not sure what to put in this
# line to make it work
print(myfunction.count)
Still missing 2 required positional arguments: 'c' and 'd'.仍然缺少 2 个必需的位置 arguments:“c”和“d”。
I hover over the 2 and it says this:我 hover 在 2 上,它说:
Expected type 'Union[Iterable, tuple, None]', got 'int' instead
You need to apply the decorator to the function whose calls you want to count by prefixing its name with a @
and putting it on the line before the function to be decorated definition.您需要将装饰器应用到 function 的调用,方法是在其名称前加上
@
前缀并将其放在要装饰定义的 function 之前的行中。 Afterwards you can use the function's original name to refer to the wrapped version because using the decorator that way is just "syntactic sugar" (see glossary ) for:之后,您可以使用函数的原始名称来引用包装版本,因为以这种方式使用装饰器只是“语法糖”(参见词汇表):
myfunction = counted_calls(myfunction)
Fixed code:固定代码:
import functools
def counted_calls(f):
@functools.wraps(f)
def count_wrapper(*args, **kwargs):
count_wrapper.count += 1
return f(*args, **kwargs)
count_wrapper.count = 0
return count_wrapper
@counted_calls # <-- Apply decorator.
def myfunction(a, b, c, d):
...
return something
integrate.quad(myfunction, 0, 1)
print(myfunction.count)
You should be wrapping myfunction
.你应该包装
myfunction
。 You do this outside the function, not inside the function you want to wrap.您在 function 外部执行此操作,而不是在您要包装的 function 内部执行此操作。
def myfunction(a, b, c, d)
# ****more of my code *****
return something
myfunction = counted_calls(myfunction)
# call the other part of your code that uses myfunction
print(myfunction.count)
You can define the decorator as a class that wraps the function.您可以将装饰器定义为包装 function 的 class。 By implementing the
__call__
method of the class, its instance can be called like functions which allows the decorator to simply return the instance as the replacement for the declared function:通过实现 class 的
__call__
方法,它的实例可以像函数一样被调用,允许装饰器简单地返回实例作为声明的 function 的替换:
class CallCounter:
def __init__(self,func):
self.func = func
self.count = 0
def __call__(self,*args,**kwargs):
self.count += 1
return self.func(*args,**kwargs)
usage:用法:
@CallCounter
def myFunction(a,b,c):
print(a,b,c)
@CallCounter
def myOtherFunction(x):
return x*5
for i in range(3):
myFunction(*map(myOtherFunction,(i,i+i,i*i)))
"""
0 0 0
5 10 5
10 20 20
"""
print(myFunction.count) # 3
print(myOtherFunction.count) # 9
In order to make it work with classes, there would be two methods to add to the CallCounter class:为了使其与类一起工作,将有两种方法添加到 CallCounter class:
def methodCaller(self,obj):
def withObject(*args,**kwargs):
return self(obj,*args,**kwargs) # inject object instance
return withObject
def __get__(self,obj,objtype=None): # return method call or CallCounter
return self.methodCaller(obj) if obj else self
Within a class, the CallCounter behaves like a property object which is accessed through the __get__
method.在 class 中,CallCounter 的行为类似于通过
__get__
方法访问的属性 object。 The __get__
method can apply to the class or to a specific object instance (obj parameter). __get__
方法可以应用于 class 或特定的 object 实例(obj 参数)。 When an instance is provided in obj, the CallCounter must inject the object in the method call otherwise there will be a missing parameter.当在 obj 中提供实例时,CallCounter 必须在方法调用中注入 object 否则将缺少参数。 This is why it returns a methodCaller function that captures and inserts the obj parameter.
这就是为什么它返回一个 methodCaller function 捕获并插入 obj 参数的原因。 When
__get__
pertains to the class itself, then the ClassCounter object is returned directly (which allows access to its count).当
__get__
属于 class 本身时,则直接返回 ClassCounter object(允许访问其计数)。
usage:用法:
class MyClass:
@CallCounter
def method1(self,s):
print("method1",s)
x = MyClass()
for i in range(3): x.method1(i**3)
print(MyClass.method1.count) # 3
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.