在 class 初始化上执行 class 方法以填充 class 属性

Execute classmethod on class initilization to fill class attribute

我正在尝试创建一个具有 class 属性的 Python class 来接收包含所有子 classes 对象的字典。

下面我在我试图完成的内容中制作了一个示例代码,但我无法在 class 初始化时制作 class 方法 运行。我觉得我正在以错误的方式解决问题,所以非常欢迎任何建议。

class Client:

    enable = True
    subclass_dict = {}
        
    def __init__(self, category, limit):
        self.category = category
        self.limit = limit
        if Client.enable == True:
            Client.enable = False
            Client.get_subclasses()
    
    
    @classmethod
    def get_subclasses(cls):
        subclasses = cls.__subclasses__()

        for subclass in subclasses:
            cls.subclass_dict[subclass().category] = subclass()
    
    
    def __str__(self):
        return f'{self.category}'

    def __repr__(self):
        return f'Client: {self.category}'

class SpecialClient(Client):

    category = 'Special'
    limit = '10_000'

    def __init__(self):
        super().__init__(SpecialClient.category, SpecialClient.limit)

class NormalClient(Client):

    category = 'Normal'
    limit = 1_000

    def __init__(self):
        super().__init__(NormalClient.category, NormalClient.limit)

有一种创建子class“注册表”的简单方法,这实际上就是您正在做的事情,但是使用 Python 3.6 中添加的通用 object.__init_subclass__() 使得通过使用它来自动创建它们的“注册表”,而不是可能必须像 get_subclasses() 方法那样递归地检查每个 subclass,subclass 的发现更简单。

我从 Subclass registration section in the PEP 487 -- Simpler customisation of class creation 提案中得到了使用 __init_subclass__() 来执行此操作的想法。由于该方法将由 all 基础 class' subclasses 继承,因此 sub-subclasses 也将自动完成注册(相反仅指向 subclasses) — 它完全消除了对像 get_subclasses().

这样的方法的需要

我已将您的代码转换为执行此操作并删除了您的 get_subclasses() 方法。里面可能还有一些无关的东西,因为我不确定你对它们的目的是什么。

class Client:
    enable = True
    subclass_dict = {}

    def __init__(self, category, limit):
        self.category = category
        self.limit = limit
        if Client.enable == True:
            Client.enable = False

    @classmethod
    def __init_subclass__(cls, /, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.subclass_dict[cls.category] = cls  # Add (sub)class to registry.

    def __str__(self):
        return f'{self.category}'

    def __repr__(self):
        return f'Client: {self.category}'


class SpecialClient(Client):
    category = 'Special'
    limit = '10_000'

    def __init__(self):
        super().__init__(SpecialClient.category, SpecialClient.limit)


class NormalClient(Client):
    category = 'Normal'
    limit = 1_000

    def __init__(self):
        super().__init__(NormalClient.category, NormalClient.limit)


if __name__ == '__main__':
    from pprint import pprint
    print('Client.subclass_dict:')
    pprint(Client.subclass_dict)

    # Verify __str__() and __repr__() were inherited.
    special = SpecialClient()
    print(f'{str(special)=!r}')
    print(f'{repr(special)=!r}')

打印的结果:

Client.subclass_dict:
{'Normal': <class '__main__.NormalClient'>,
 'Special': <class '__main__.SpecialClient'>}
str(special)='Special'
repr(special)='Client: Special'