【问题标题】:Executing code after construction of class object构造类对象后执行代码
【发布时间】:2013-07-21 00:00:38
【问题描述】:

我希望通过让每个子类将自己注册到父类持有的列表中来制作给定类的所有子类的列表,例如:

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

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

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

您似乎想要创建某种元类的子类,该子类正在创建所有内容以向 Monster 注册它?或者这完全不符合标准

【问题讨论】:

    标签: python


    【解决方案1】:

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

    >>> 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,但该方法存在于所有支持新型类(2.2 及更高版本,一直到 3.x)的 Python 版本中。

    否则,挂钩到类创建的规范方法是定义一个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

    【讨论】:

    • 太棒了。我以为我想要这样的东西,但我不知道如何使用元类。
    【解决方案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'>]
    

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-14
        • 2017-01-03
        • 1970-01-01
        • 2023-03-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多