#python #class #counter #instance-variables
#python #класс #счетчик #переменные экземпляра
Вопрос:
Я хотел бы отслеживать количество функций внутри класса, но так, чтобы это количество отличалось для каждого экземпляра класса.
Мы можем настроить счетчик для простой функции:
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)
невозможно установить счетчик для метода ЭКЗЕМПЛЯРА:
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
конкретный экземпляр конкретным? Так что a
и b
может иметь несколько значений foo2.count
?
Пожалуйста, обратите внимание: я спрашиваю об атрибуте функции, а не об атрибуте класса.
Ответ №1:
Может быть, это тогда?
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. Нравится ваша идея, но что произойдет, если экземпляр класса тяжелый? Допустим, вы создали 1 миллион экземпляров, тогда этот словарь может быть большим? Или это не имеет значения, потому что size (hash (self)) << размер (self) ?
Ответ №2:
используйте __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
Комментарии:
1. count_foo2 является атрибутом экземпляра класса, а не функции. Я спрашивал об атрибуте функции.
2. вы должны решить, является ли count атрибутом функции или экземпляра класса… Судя по всему, ваше использование указывает на то, что это должен быть атрибут экземпляра. Почему бы вам не рассказать нам о реальной проблеме, которую вы пытаетесь решить, это звучит как проблема XY…
3. Я хотел бы создать декоратор класса «счетчик», который отслеживает, сколько раз выполнялась функция, но только «внутри» этого конкретного экземпляра класса. Я надеялся избежать создания атрибутов экземпляра (как в вашем примере) и работать с функциями напрямую
Ответ №3:
Вот моя попытка. Я не уверен, что это полностью то, что вы хотите, поскольку в одном из ваших комментариев вы указали, что вам нужны конкретные атрибуты экземпляра функции (?). Однако, похоже, это ведет себя так, как вы описали. Преимущество заключается в том, что он работает независимо от того, сколько методов, для которых вы хотите, чтобы это поведение имело место.
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__]}')
# ...
Комментарии:
1. Спасибо за ваш ответ. Я должен согласиться с Жюльеном, потому что он был первым, кто придумал способ создания функции, а не атрибута класса, но я ценю вашу помощь и усилия!