我想跟踪从基类派生的所有类实例,如果以下方法很常见,或者它存在严重的陷阱,我很好奇。那就是模式还是反模式?
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
缓存吗?
答案 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.