我有一个我要注册的类层次结构,以便以后可以访问它。到目前为止,我一直在手动执行此操作:
class FirstClass(MyBaseClass):
....
registry.register(FirstClass)
class SecondClass(FirstClass):
....
registry.register(SecondClass)
我正在寻找一种在评估类时调用registry.register(Class)
的方法(也就是说,有人用类导入包),而不必明确地调用它。
我想我必须在MyBaseClass
添加一些内容,但我无法弄清楚是什么。所有特殊方法似乎都与实例相关,而不是与类相关。
有办法吗?
说明: Registry跟踪从BaseClass派生的类。在代码中的某个时刻,我将遍历所有这些类并实例化对象。它有点复杂,因为注册表也在做其他事情,但这是主要的想法。
答案 0 :(得分:2)
这是完全元类的用途:将操作应用于整个类的层次结构:
In [1]: def register(cls):
...: # just to show when it is called.
...: print('Register: {}'.format(cls))
...:
...:
...: class MyMeta(type):
...: def __new__(cls, name, bases, attrs):
...: the_cls = super().__new__(cls, name, bases, attrs)
...: register(the_cls)
...: return the_cls
In [2]: class FirstClass(metaclass=MyMeta):
...: pass
...:
Register: <class '__main__.FirstClass'>
In [3]: class SecondClass(FirstClass):
...: pass
...:
Register: <class '__main__.SecondClass'>
请注意,您必须仅在层次结构的根中添加元类,并且它将在所有子类中继承,因此您只需将其添加到MyBaseClass
即可。
如需深入解释,请参阅此问题:What is a metaclass in Python?
我使用了python3语法。在python2中添加元类,您必须设置__metaclass__
属性:
class MyClass(object):
__metaclass__ = MyMeta
我想指出,要获取类的子类,可以使用__subclasses__
方法。没有必要明确地跟踪它们,不要使用自定义元类:
In [4]: FirstClass.__subclasses__()
Out[4]: [__main__.SecondClass]
答案 1 :(得分:2)
Python会自动跟踪任何新式类的直接子类(具有object
作为其基类的类或由此派生的基类)在名为__subclasses__
的类属性中定义。这意味着您不必自己手动注册它们。
要获得整个继承层次结构,您需要递归地收集每个子类的属性内容。这就是我的意思:
class MyBaseClass(object): pass
class FirstClass(MyBaseClass): pass
class SecondClass(FirstClass): pass
def get_subclasses(cls):
return cls.__subclasses__() + [g for s in cls.__subclasses__()
for g in get_subclasses(s)]
print(get_subclasses(MyBaseClass))
输出:
[<class '__main__.FirstClass'>, <class '__main__.SecondClass'>]
答案 2 :(得分:0)
我最近的项目需要跟踪类,我最初的方法是使用globals()或类似的东西来查找类,但irc.freenode.org #python中的pythonistas建议使用像这样的装饰器和它看起来真的是pythonic:
registry = {}
def registered(cls):
registry[cls.__name__] = cls
return cls
@registered
class Foo:
"""
"""
@registered
class Bar:
"""
"""
导入此文件时,file.registry将包含其中的所有类,并使用注册表['Class_Name']进行查找。在我们的用例中,我们选择了基于Class_Name配置的类实现。