计算 Python 中使用元类的实例数
Count number of instances using a metaclass in Python
我写了一个 metaclass,它计算每个子 class 的实例数。
所以我的 meta 有一个像 {classname: number_of_instances}
.
这样的 dict
这是实现:
class MetaCounter(type):
_counter = {}
def __new__(cls, name, bases, dict):
cls._counter[name] = 0
return super().__new__(cls, name, bases, dict)
def __call__(cls, *args, **kwargs):
cls._counter[cls.__name__] += 1
print(f'Instantiated {cls._counter[cls.__name__]} objects of class {cls}!')
return super().__call__(*args, **kwargs)
class Foo(metaclass=MetaCounter):
pass
class Bar(metaclass=MetaCounter):
pass
x = Foo()
y = Foo()
z = Foo()
a = Bar()
b = Bar()
print(MetaCounter._counter)
# {'Foo': 3, 'Bar': 2} --> OK!
print(Foo._counter)
# {'Foo': 3, 'Bar': 2} --> I'd like it printed just "3"
print(Bar._counter)
# {'Foo': 3, 'Bar': 2} --> I'd like it printed just "2"
它工作正常,但我想添加一个信息隐藏级别。也就是说,metaclass 是 MetaCounter 的 classes 不应该有其他 [=53] 实例的计数器=]es 具有相同的元。他们应该只知道有关 他们的 实例数量的信息。
所以 MetaCounter._counter
应该显示整个 dict,但是 Foo._counter
(设 Foo 是 class 和 MetaCounter 作为它的 metaclass) 应该只是 return Foo 的数量实例。
有办法实现吗?
我试图重写 __getattribute__
,但结果却搞乱了计数逻辑。
我也试过将_counter
作为属性放在__new__
方法的dict
参数中,但后来它也变成了一个实例成员,我不想所以。
我对元class的了解还不够多,不能说做你正在尝试的事情是否是个坏主意,但这是可能的。
您可以让 MetaCounter
只保留对其“元classed”classes 的引用,并通过更新 dict
为每个实例添加一个特定的实例计数器在 MetaCounter.__new__
方法中:
class MetaCounter(type):
_classes = []
def __new__(cls, name, bases, dict):
dict.update(_counter=0)
metaclassed = super().__new__(cls, name, bases, dict)
cls._classes.append(metaclassed)
return metaclassed
每次实例化新的 MetaCounter
class 时,您都会递增计数器
def __call__(cls, *args, **kwargs):
cls._counter += 1
print(f'Instantiated {cls._counter} objects of class {cls}!')
return super().__call__(*args, **kwargs)
这确保每个 MetaCounter
class 拥有自己的实例计数器并且不知道其他 MetaCounter
classes.
然后,要获得所有计数器,您可以向 MetaCounter
添加一个 _counters
静态方法,其中 returns 每个 MetaCounter
class 的计数器]:
@classmethod
def _counters(cls):
return {klass: klass._counter for klass in cls._classes}
那么你就完成了:
print(MetaCounter._counters()) # {<class '__main__.Foo'>: 3, <class '__main__.Bar'>: 2}
print(Foo._counter) # 3
print(Bar._counter) # 2
这是一个工作示例,使用 描述符 根据 实例是否访问它来修改 _counter
属性的行为(class)或 class(本例中的 metaclass)
class descr:
def __init__(self):
self.counter = {}
self.previous_counter_value = {}
def __get__(self, instance, cls):
if instance:
return self.counter[instance]
else:
return self.counter
def __set__(self, instance, value):
self.counter[instance] = value
class MetaCounter(type):
_counter = descr()
def __new__(cls, name, bases, dict):
new_class = super().__new__(cls, name, bases, dict)
cls._counter[new_class] = 0
return new_class
def __call__(cls, *args, **kwargs):
cls._counter += 1
print(f'Instantiated {cls._counter} objects of class {cls}!')
return super().__call__(*args, **kwargs)
我写了一个 metaclass,它计算每个子 class 的实例数。
所以我的 meta 有一个像 {classname: number_of_instances}
.
这是实现:
class MetaCounter(type):
_counter = {}
def __new__(cls, name, bases, dict):
cls._counter[name] = 0
return super().__new__(cls, name, bases, dict)
def __call__(cls, *args, **kwargs):
cls._counter[cls.__name__] += 1
print(f'Instantiated {cls._counter[cls.__name__]} objects of class {cls}!')
return super().__call__(*args, **kwargs)
class Foo(metaclass=MetaCounter):
pass
class Bar(metaclass=MetaCounter):
pass
x = Foo()
y = Foo()
z = Foo()
a = Bar()
b = Bar()
print(MetaCounter._counter)
# {'Foo': 3, 'Bar': 2} --> OK!
print(Foo._counter)
# {'Foo': 3, 'Bar': 2} --> I'd like it printed just "3"
print(Bar._counter)
# {'Foo': 3, 'Bar': 2} --> I'd like it printed just "2"
它工作正常,但我想添加一个信息隐藏级别。也就是说,metaclass 是 MetaCounter 的 classes 不应该有其他 [=53] 实例的计数器=]es 具有相同的元。他们应该只知道有关 他们的 实例数量的信息。
所以 MetaCounter._counter
应该显示整个 dict,但是 Foo._counter
(设 Foo 是 class 和 MetaCounter 作为它的 metaclass) 应该只是 return Foo 的数量实例。
有办法实现吗?
我试图重写 __getattribute__
,但结果却搞乱了计数逻辑。
我也试过将_counter
作为属性放在__new__
方法的dict
参数中,但后来它也变成了一个实例成员,我不想所以。
我对元class的了解还不够多,不能说做你正在尝试的事情是否是个坏主意,但这是可能的。
您可以让 MetaCounter
只保留对其“元classed”classes 的引用,并通过更新 dict
为每个实例添加一个特定的实例计数器在 MetaCounter.__new__
方法中:
class MetaCounter(type):
_classes = []
def __new__(cls, name, bases, dict):
dict.update(_counter=0)
metaclassed = super().__new__(cls, name, bases, dict)
cls._classes.append(metaclassed)
return metaclassed
每次实例化新的 MetaCounter
class 时,您都会递增计数器
def __call__(cls, *args, **kwargs):
cls._counter += 1
print(f'Instantiated {cls._counter} objects of class {cls}!')
return super().__call__(*args, **kwargs)
这确保每个 MetaCounter
class 拥有自己的实例计数器并且不知道其他 MetaCounter
classes.
然后,要获得所有计数器,您可以向 MetaCounter
添加一个 _counters
静态方法,其中 returns 每个 MetaCounter
class 的计数器]:
@classmethod
def _counters(cls):
return {klass: klass._counter for klass in cls._classes}
那么你就完成了:
print(MetaCounter._counters()) # {<class '__main__.Foo'>: 3, <class '__main__.Bar'>: 2}
print(Foo._counter) # 3
print(Bar._counter) # 2
这是一个工作示例,使用 描述符 根据 实例是否访问它来修改 _counter
属性的行为(class)或 class(本例中的 metaclass)
class descr:
def __init__(self):
self.counter = {}
self.previous_counter_value = {}
def __get__(self, instance, cls):
if instance:
return self.counter[instance]
else:
return self.counter
def __set__(self, instance, value):
self.counter[instance] = value
class MetaCounter(type):
_counter = descr()
def __new__(cls, name, bases, dict):
new_class = super().__new__(cls, name, bases, dict)
cls._counter[new_class] = 0
return new_class
def __call__(cls, *args, **kwargs):
cls._counter += 1
print(f'Instantiated {cls._counter} objects of class {cls}!')
return super().__call__(*args, **kwargs)