Я хотел бы отслеживать количество функций внутри класса, но так, чтобы это количество было разным для каждого экземпляра класса.
Мы можем настроить счетчик на простую функцию:
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
?
Обратите внимание: я спрашиваю об атрибуте функции, а не об атрибуте класса.
используйте метод __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 атрибутом функции или экземпляра класса... В любом случае ваше использование, похоже, указывает на то, что это должен быть атрибут экземпляра. Почему бы вам не рассказать нам о реальной проблеме, которую вы пытаетесь решить, это звучит как проблема XY...
Я хотел бы создать декоратор класса «счетчик», который отслеживает, сколько раз выполнялась функция, но только «внутри» этого конкретного экземпляра класса. Я надеялся избежать создания атрибутов экземпляра (как в вашем примере) и напрямую работать с функциями.
Может тогда это?
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) ?
Вот моя попытка. Я не уверен, что это полностью то, что вы хотите, поскольку в одном из ваших комментариев вы указали, что вам нужны конкретные атрибуты экземпляра функции (?). Однако это, похоже, ведет себя так, как вы описали. Преимущество заключается в том, что он работает независимо от того, для скольких методов вы хотите, чтобы это поведение имело место.
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__]}')
# ...
Спасибо за ваш ответ. Я должен принять Жюльена, потому что он был первым, кто придумал способ создания функции, а не атрибута класса, но я ценю вашу помощь и усилия!
count_foo2 — это атрибут экземпляра класса, а не функции. Я спрашивал об атрибуте функции.