使用元类来跟踪 python 中的实例

Fra*_*y_V 5 python metaclass python-3.x

我需要跟踪某些类的实例(并对这些类执行其他操作)。我希望不必在相关类中声明任何额外的代码,因此理想情况下所有内容都应该在元类中处理。

我不知道如何向这些类的每个新实例添加弱引用。例如:

class Parallelizable(type):
    def __new__(cls, name, bases, attr):
        meta = super().__new__(cls, name, bases, attr)
        # storing the instances in this WeakSet
        meta._instances = weakref.WeakSet()
        return meta

    @property
    def instances(cls):
        return [x for x in cls._instances]

class Foo(metaclass=Parallelizable)
    def __init__(self, name):
        super().__init__()
        self.name = name

        # I would like to avoid having to do that - instead have the metaclass manage it somehow
        self._instances.add(self)
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?我似乎无法在元类方面找到一个钩子来进入__init__Foo 的......

jsb*_*eno 5

当元类的“附属”类的每个新实例为 时调用的元类上的方法__call__。如果您将记录实例的代码放在那里,这就是您需要做的全部工作:


from weakref import WeakSet

# A convenient class-level descriptor to retrieve the instances:

class Instances:
    def __get__(self, instance, cls):
        return [x for x in cls._instances]

class Parallelizable(type):
    def __init__(cls, name, bases, attrs, **kw):
        super().__init__(name, bases, attrs, **kw)
        cls._instances = WeakSet()
        cls.instances = Instances()

    def __call__(cls, *args, **kw):
        instance = super().__call__(*args, **kw)
        cls._instances.add(instance)
        return instance

Run Code Online (Sandbox Code Playgroud)

相同的代码在没有描述符的情况下也可以工作——这只是一个拥有报告实例的类属性的好方法。但如果 WeakSet 就足够了,那么这段代码就足够了:


from weakref import WeakSet
class Parallelizable(type):
    def __init__(cls, name, bases, attrs, **kw):
        super().__init__(name, bases, attrs, **kw)
        cls.instances = WeakSet()

    def __call__(cls, *args, **kw):
        instance = super().__call__(*args, **kw)
        cls.instances.add(instance)
        return instance

Run Code Online (Sandbox Code Playgroud)