3

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

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

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

我知道 __subclass__ 具有此功能,但我想知道(为了我自己的启发)您将如何自己实现它。

看起来你想要创建某种元类的子类,它正在创建所有东西来向 Monster 注册它?或者这完全不符合要求

4

3 回答 3

11

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

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

.__subclasses__()返回当前仍然存在的子类的列表。如果您曾经清除对Yeti(del Yeti在模块中,删除所有实例、子类、导入等) 的所有引用,那么当您调用.__subclasses__(). 请注意,本质上,.__subclasses__()是一个CPython implementation detail,但该方法存在于所有支持新样式类的 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

演示:

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

或者您可以使用类装饰器

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类型,或使用显式装饰器。

无论哪种方式,元类或类装饰器都会注册一个永久引用。如果您真的非常想模仿这种行为,您可以使用该weakref模块。.__subclasses__()

于 2013-07-22T09:50:21.363 回答
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'>]
于 2013-07-22T09:51:13.637 回答
1

只是为了保留您的代码,请在其定义之外添加类:

class Monster(object):
    monsters = list()

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

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

但是,如前所述:如果这是一个通用功能,请创建一个元类

于 2013-07-22T10:03:21.780 回答