@ritamiskas

Как считать количество выполненений методов импортированного класса?

Хочется максимально просто посчитать количество запусков в процессе выполнения скрипта различных методов импортированного класса. Что для этого лучше всего подойдет? И как это осуществить на простом примере?
  • Вопрос задан
  • 84 просмотра
Пригласить эксперта
Ответы на вопрос 3
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)

Но так придется прописывать декоратор перед каждым методом. Возможно как-то можно сдекорировать класс целиком.
Ответ написан
@Taus
Если в классе нет дескрипторов с вызываемыми объектами, кроме простых classmethod и staticmethod, то задачу можно решить таким образом:
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)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы