在构造类对象后执行代码

Vik*_*esh 3 python

我希望通过让每个子类在父类保存的列表中注册自己来创建给定类的所有子类的列表,即类似这样的事情:

class Monster(object):
    monsters = list()
class Lochness(Monster):
    Monster.monsters.append(Lochness)
class Yeti(Monster):
    Monster.monsters.append(Yeti)
Run Code Online (Sandbox Code Playgroud)

这显然不起作用,因为当我想将它们添加到列表中时尚未创建类.而且,如果它是自动完成的话会更好(比如__subclass__)

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

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

Mar*_*ers 11

已经注册了定义的子类; 调用class.__subclasses__()方法获取列表:

>>> class Monster(object):
...     pass
... 
>>> class Lochness(Monster):
...     pass
... 
>>> class Yeti(Monster):
...     pass
... 
>>> Monster.__subclasses__()
[<class '__main__.Lochness'>, <class '__main__.Yeti'>]
Run Code Online (Sandbox Code Playgroud)

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

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

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
Run Code Online (Sandbox Code Playgroud)

演示:

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

或者您可以使用类装饰器:

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
Run Code Online (Sandbox Code Playgroud)

演示:

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

不同之处在于你负责注册怪物; 使用基MonstersMeta类型或使用显式装饰器.

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