问题
I want to create a settings registry. I also want to be able to group settings in macro-categories.
The following simplified example works with a single registry:
class RegistryHolder:
registry = {}
def __init_subclass__(cls, setting_name=None, **kwargs):
super().__init_subclass__(**kwargs)
cls.registry[setting_name] = cls
class SettingOne(RegistryHolder, setting_name='SettingOne'):
pass
class SettingTwo(RegistryHolder, setting_name='SettingTwo'):
pass
And the result is:
print(RegistryHolder.registry)
{'SettingOne': <class '__main__.SettingOne'>,
'SettingTwo': <class '__main__.SettingTwo'>}
I would like to group the settings by macro categories without rewriting the __init_subclass__()
each time. Something like:
class UserRegistryHolder(RegistryHolder):
pass
class SettingOne(UserRegistryHolder, setting_name='SettingOne'):
pass
class SettingTwo(UserRegistryHolder, setting_name='SettingOne'):
pass
class SystemRegistryHolder(RegistryHolder):
pass
class SettingA(SystemRegistryHolder, setting_name='SettingA'):
pass
class SettingB(SystemRegistryHolder, setting_name='SettingB'):
pass
This obviously does not work because when I subclass the RegistryHolder
, I am 'registering' the User/System
classes as part of the registry, e.g. for UserRegistryHolder.registry
I get:
{'SettingOne': <class '__main__.SettingTwo'>,
'SettingTwo': <class '__main__.SettingTwo'>,
None: <class '__main__.UserRegistryHolder'>}
So a few questions:
- Am I aksing the wrong question?
- Am I overthinking it?
- How would you go about creating such an interface cleanly (alternatives are welcome)?
回答1:
Assuming that RegistryHolder
is only a base class (template) and should not accumulate all settings, while its sub-holders UserRegistryHolder/SystemRegistryHolder
are expected do keep the "respective" settings:
class RegistryHolder:
registry = {}
def __init_subclass__(cls, setting_name=None, **kwargs):
super().__init_subclass__(**kwargs)
parent = cls.__bases__[0]
if setting_name:
parent.registry[setting_name] = cls # add setting to parent sub-holder
else:
cls.registry = {} # init registry for sub-holder
class UserRegistryHolder(RegistryHolder):
pass
class SettingOne(UserRegistryHolder, setting_name='SettingOne'):
pass
class SettingTwo(UserRegistryHolder, setting_name='SettingTwo'):
pass
class SystemRegistryHolder(RegistryHolder):
pass
class SettingA(SystemRegistryHolder, setting_name='SettingA'):
pass
class SettingB(SystemRegistryHolder, setting_name='SettingB'):
pass
print(RegistryHolder.registry)
print(UserRegistryHolder.registry)
print(SystemRegistryHolder.registry)
The output (consecutively):
{}
{'SettingOne': <class '__main__.SettingOne'>, 'SettingTwo': <class '__main__.SettingTwo'>}
{'SettingA': <class '__main__.SettingA'>, 'SettingB': <class '__main__.SettingB'>}
来源:https://stackoverflow.com/questions/57626912/registry-pattern-with-init-subclass-and-sub-classable-registry