在构造类对象后执行代码

时间:2013-07-22 09:47:39

标签: python

我希望通过让每个子类在父类所拥有的列表中注册自己来创建给定类的所有子类的列表,例如:

class Monster(object):
    monsters = list()
class Lochness(Monster):
    Monster.monsters.append(Lochness)
class Yeti(Monster):
    Monster.monsters.append(Yeti)

这显然不起作用,因为当我想将它们添加到列表中时尚未创建类。并且,如果它是自动完成的(例如__subclass __)

,它会更好

我知道__subclass__有这个功能,但我想知道(我自己的启发)你自己如何实现它。

看起来你想创建某种类元类的子类,它创建了一些用Monster注册它的东西?或者完全偏离基础

3 个答案:

答案 0 :(得分:11)

已经注册定义了哪些子类;调用class.__subclasses__() method获取列表:

>>> class Monster(object):
...     pass
... 
>>> class Lochness(Monster):
...     pass
... 
>>> class Yeti(Monster):
...     pass
... 
>>> Monster.__subclasses__()
[<class '__main__.Lochness'>, <class '__main__.Yeti'>]

.__subclasses__()返回当前仍然存在的子类的列表。如果您要清除对模块中Yetidel Yeti的所有引用,删除所有实例,子类,导入等),那么当您调用.__subclasses__()时它将不再列出。请注意,实质上,.__subclasses__()CPython implementation detail,但该方法存在于支持新式类的所有Python版本中(2.2及以上,一直到3.x)。

否则,挂钩到类创建的规范方法是定义metaclass

class MonstersMeta(type):
    def __new__(metaclass, name, bases, namespace):
        cls = super(MonstersMeta, metaclass).__new__(metaclass, name, bases, namespace)
        if issubclass(cls, Monster) and not cls is Monster:
            Monster.monsters.append(cls)
        return cls

class Monster(object):
    __metaclass__ = MonstersMeta
    monsters = []

class Lochness(Monster):
    pass

class Yeti(Monster):
    pass

演示:

>>> class Monster(object):
...     __metaclass__ = MonstersMeta
...     monsters = []
... 
>>> class Lochness(Monster):
...     pass
... 
>>> class Yeti(Monster):
...     pass
... 
>>> Monster.monsters
[<class '__main__.Lochness'>, <class '__main__.Yeti'>]

或者您可以使用class decorator

def registered_monster(cls):
    Monster.monsters.append(cls)
    return cls

class Monster(object):
    monsters = []

@registered_monster
class Lochness(Monster):
    pass

@registered_monster
class Yeti(Monster):
    pass

演示:

>>> class Monster(object):
...     monsters = []
... 
>>> @registered_monster
... class Lochness(Monster):
...     pass
... 
>>> @registered_monster
... class Yeti(Monster):
...     pass
... 
>>> Monster.monsters
[<class '__main__.Lochness'>, <class '__main__.Yeti'>]

不同之处在于你承担了登记怪物的责任;使用基本MonstersMeta类型或使用显式装饰器。

无论哪种方式,元类或类装饰器都会注册一个永久引用。如果您确实想要模仿.__subclasses__()行为,则可以使用weakref module

答案 1 :(得分:2)

除了本案例的明显解决方案使用type.__subclasses__()之外,您可以使用装饰器来解决类似的问题:

class Monster(object):
    monsters = list()

def isMonster(cls):
    Monster.monsters.append(cls)
    return cls

@isMonster
class Lochness(Monster):
    pass

@isMonster
class Yeti(Monster):
    pass

print(Monster.monsters) # [<class '__main__.Lochness'>, <class '__main__.Yeti'>]

答案 2 :(得分:1)

只是为了保留你的代码,在他们的定义之外添加类:

class Monster(object):
    monsters = list()

class Lochness(Monster):
    pass
Monster.monsters.append(Lochness)

class Yeti(Monster):
    pass 
Monster.monsters.append(Yeti)

但是,如上所述:如果这是一个常见功能,请创建一个Metaclass