import json
class Test:
def method1(self):
pass
def method2(self):
pass
# Через оборачивания
class CounterUseMethod:
count_method = {}
@classmethod
def counter(cls, method):
def wrapper(self, *args, **kwargs):
name = f'{self.__class__.__name__}: {method.__name__}'
if name not in cls.count_method:
cls.count_method[name] = 0
cls.count_method[name] += 1
return method(self, *args, **kwargs)
return wrapper
Test.method1 = CounterUseMethod.counter(Test.method1)
Test.method2 = CounterUseMethod.counter(Test.method2)
# Через наследование
class Counter(Test):
count_method = {}
def method1(self):
name = 'method1'
if name not in self.count_method:
self.count_method[name] = 0
self.count_method[name] += 1
return super().method1()
def method2(self):
name = 'method2'
if name not in self.count_method:
self.count_method[name] = 0
self.count_method[name] += 1
return super().method2()
test = Test()
test2 = Counter()
for _ in range(10):
test.method1()
test2.method1()
for _ in range(5):
test.method2()
test2.method2()
print(json.dumps(CounterUseMethod.count_method, indent=4))
print(json.dumps(test2.count_method, indent=4))
def counter(func): #декоратор-счётчик
def wrapper(*args, **kwargs):
global counts
func(*args, **kwargs)
counts[func.__name__] = counts.get(func.__name__, 0) + 1
return wrapper
class Car():
def __init__(self, speed=100):
self.speed = speed
@counter
def up_speed(self, delta):
self.speed += delta
@counter
def down_speed(self, delta):
self.speed -= delta
def __str__(self):
return 'Current speed equal ' + str(self.speed)
counts = dict()
x = Car()
print(x)
x.up_speed(10)
x.up_speed(20)
x.up_speed(30)
x.down_speed(100)
print(x)
print(counts)
import functools
from collections import defaultdict
from pprint import pprint
class A:
def method_a(self):
pass
def method_b(self):
pass
@classmethod
def classmethod_a(cls):
pass
@staticmethod
def staticmethod_a():
pass
def add_class_to_counter(counter, cls, *, methods=None):
def count(name):
def decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
counter[name] += 1
# classmethod и staticmethod - дескрипторы и не имеют __call__
# Явно вызываем
if isinstance(f, classmethod) or isinstance(f, staticmethod):
return f.__get__(None, cls)
return f(*args, **kwargs)
return wrapper
return decorator
if methods:
count_methods = methods
else:
count_methods = (name for name in cls.__dict__ if not name.startswith('_') and callable(getattr(cls, name)))
for method in count_methods:
attribute = vars(cls)[method]
setattr(cls, method, count(getattr(cls, method).__qualname__)(attribute))
calls_counter = defaultdict(int)
add_class_to_counter(calls_counter, A)
a = A()
for _ in range(10):
a.method_a()
a.method_a()
a.method_b()
a.classmethod_a()
A.classmethod_a()
A.staticmethod_a()
pprint(calls_counter)