使用基类成员来跟踪派生类实例

时间:2015-03-17 22:00:21

标签: python inheritance

我想跟踪从基类派生的所有类实例,如果以下方法很常见,或者它存在严重的陷阱,我很好奇。那就是模式还是反模式?

class Animal(object):
    all_animals = []
    def __init__(self):
        self.all_animals.append(self)

class Dog(Animal):
    def __init__(self):
        # Do stuff here...
        super(Dog, self).__init__()

class Person(Animal):
    def __init__(self):
        # Do other stuff here...
        super(Person, self).__init__()

这是推荐的做事方式吗?当继承在大型项目或大量文件上发生时,此方法是否有任何问题?例如,我可以依赖一致的Animal.all_animals缓存吗?

1 个答案:

答案 0 :(得分:1)

您的方法中的一个问题是,一旦没有更多的引用,该列表将阻止实例被垃圾回收。因此,如果实例是可清除的并且实例的顺序无关紧要,那么我们可以使用weakref.WeakSet来存储实例,而不是将实例存储在__init__方法中,我们可以使用Metaclass来执行此操作创建一个实例。(如果需要列表,可以使用PyPI的weakreflist包)

当我们实例化一个类时,首先调用它的Metaclass __call__方法,我们可以将实例存储在WeakSet中。除此之外,如果我们仅允许all_animals类访问Animal会更有意义,所以我使用了descriptor __get__方法只允许我们从Animal类访问它。

from weakref import WeakSet


class Meta(type):
    def __call__(self):
        instance = super(Meta, self).__call__()
        Animal.all_animals.add(instance)
        return instance


class Animals_prop(object):

    def __init__(self, cls=WeakSet):
        self.all_animals = cls()

    def __get__(self, ins, cls):
        if ins is None and cls is Animal:
            return self.all_animals
        else:
            raise AttributeError


class Animal(object):
    __metaclass__ = Meta
    all_animals = Animals_prop()

    def __del__(self):
        print "{}'s instance is dead.".format(type(self).__name__)


class Dog(Animal):
    pass


class Person(Animal):
    pass


if __name__ == '__main__':
    a = Animal()
    b = Dog()
    c = Person()
    print set(Animal.all_animals)
    del c
    print set(Animal.all_animals)
    print '-'*10

<强>输出:

set([<__main__.Animal object at 0x1012f5590>, <__main__.Dog object at 0x1012f55d0>, <__main__.Person object at 0x1012f5610>])
Person's instance is dead.
set([<__main__.Animal object at 0x1012f5590>, <__main__.Dog object at 0x1012f55d0>])
----------
Animal's instance is dead.
Dog's instance is dead.