Как создать счетчик функций для конкретного экземпляра?

Я хотел бы отслеживать количество функций внутри класса, но так, чтобы это количество было разным для каждого экземпляра класса.

Мы можем настроить счетчик на простую функцию:

def foo1():
    pass

foo1.count = 0
foo1.count +=1
print(foo1.count)

Теперь обратимся к методам класса:

class A:
    def foo2(self):
        print('Hi')

мы также можем установить счетчик здесь

A.foo2.count = 0
a = A()
b = A()

но этот счет НЕ зависит от экземпляра

A.foo2.count += 1
print(a.foo2.count)
print(b.foo2.count)

невозможно установить количество для метода INSTANCE:

a.foo2.count += 1

и если мы используем __func__ , это будет эквивалентно изменению A.foo2.count:

a.foo2.__func__.count += 1
print(b.foo2.count)
print(a.foo2.count)
print(A.foo2.count)

Вопрос: как сделать foo2.count INSTANCE конкретным? Чтобы a и b могли иметь несколько значений foo2.count?

Обратите внимание: я спрашиваю об атрибуте функции, а не об атрибуте класса.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
87
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

используйте метод __init__:

class A:

    def __init__(self):
        self.count_foo2 = 0

    def foo2(self):
        print('Hi')
        self.count_foo2 += 1 


a = A()
b = A()

a.foo2()

print(a.count_foo2)
print(b.count_foo2)

Выход:

Hi
1
0

count_foo2 — это атрибут экземпляра класса, а не функции. Я спрашивал об атрибуте функции.

Kreol 15.12.2020 03:00

вы должны решить, является ли count атрибутом функции или экземпляра класса... В любом случае ваше использование, похоже, указывает на то, что это должен быть атрибут экземпляра. Почему бы вам не рассказать нам о реальной проблеме, которую вы пытаетесь решить, это звучит как проблема XY...

Julien 15.12.2020 03:05

Я хотел бы создать декоратор класса «счетчик», который отслеживает, сколько раз выполнялась функция, но только «внутри» этого конкретного экземпляра класса. Я надеялся избежать создания атрибутов экземпляра (как в вашем примере) и напрямую работать с функциями.

Kreol 15.12.2020 03:10
Ответ принят как подходящий

Может тогда это?

from collections import defaultdict


def foo1():
    print('Hi')
foo1.count = defaultdict(int)

class A:

    def foo2(self):
        foo1()
        foo1.count[self] += 1



a = A()
b = A()

a.foo2()
a.foo2()
b.foo2()

print(foo1.count)

выход:

Hi
Hi
Hi
defaultdict(<class 'int'>, {<__main__.A object at 0x000001E59759ABE0>: 2, <__main__.A object at 0x000001E596AFCD30>: 1})

Нравится ваша идея, но что произойдет, если экземпляр класса будет тяжелым? Скажем, вы создали 1 миллион экземпляров, тогда этот словарь может быть большим? Или это не имеет значения, потому что size(hash(self)) << size(self) ?

Kreol 15.12.2020 05:17

Вот моя попытка. Я не уверен, что это полностью то, что вы хотите, поскольку в одном из ваших комментариев вы указали, что вам нужны конкретные атрибуты экземпляра функции (?). Однако это, похоже, ведет себя так, как вы описали. Преимущество заключается в том, что он работает независимо от того, для скольких методов вы хотите, чтобы это поведение имело место.

def fn_exec_count(base_fn):
    def new_fn(self, *args, **kwargs):
        fn_count_attr = 'fn_' + base_fn.__name__ + '_count'
        if not hasattr(self, fn_count_attr):
            setattr(self, fn_count_attr, 1)
        else:
            setattr(self, fn_count_attr, getattr(self, fn_count_attr) + 1)
        base_fn(self, *args, **kwargs)
    new_fn.__name__ = base_fn.__name__
    return new_fn

class A:
    @fn_exec_count
    def foo(self):
        fn_count_attr = 'fn_' + A.foo.__name__ + '_count' 
        print(f'Value of counter: {getattr(self, fn_count_attr, None)}')


a1 = A()
a1.foo()
a1.foo()
a2 = A()
a2.foo()
a1.foo()

Выходы:

Value of counter: 1
Value of counter: 2
Value of counter: 1
Value of counter: 3

Обновлено: кража из ответа Жюльена на использование defaultdict делает это немного менее подробным.

def fn_exec_count_dict(base_fn):
    def new_fn(self, *args, **kwargs):
        if not hasattr(self, 'fn_exec_count'):
            setattr(self, 'fn_exec_count', defaultdict(int))
        self.fn_exec_count[base_fn.__name__] += 1
        base_fn(self, *args, **kwargs)
    new_fn.__name__ = base_fn.__name__
    return new_fn

class A:
    @fn_exec_count_dict
    def foo(self):
        print(f'Value of counter: {self.fn_exec_count[A.foo.__name__]}')

# ...

Спасибо за ваш ответ. Я должен принять Жюльена, потому что он был первым, кто придумал способ создания функции, а не атрибута класса, но я ценю вашу помощь и усилия!

Kreol 16.12.2020 01:21

Другие вопросы по теме