I have an abstract base class that, which hosts data in the form of a numpy array, knows how to work this data, and which can explain matplotlib how to draw it. To accomodate different types of data, it has a number of subclasses, like this:
class PlotData():
"""Base Class"""
subclasslist = []
@classmethod
def register(cls):
super().subclasslist.append(cls)
def __new__(self, initdata, *args, **kwargs):
for subclass in subclasslist:
try:
subclass.__test__(initdata)
except AssertionError:
continue
else:
break
else:
raise TypeError("Initdata does not fit any known subclass")
return subclass(initdata, *args, **kwargs)
class Plot3D(PlotData):
"""Subclass for 3d-plotting data"""
def __test__(initdata):
assert Data_is_the_right_kind
class Plot_XY(PlotData):
"""Subclass for for plotting X-Y relations of data"""
def __test__(initdata):
assert Data_is_the_right_kind
now, the issue is how to get the class references into the subclasslist. At first I wanted to call super().register() in the class body, but im unable to get a reference to the class itself, which is what I want to store in the list. A small search has yielded two possible solutions, and I was wondering what the best one was.
Adding a call after each class definition, like this:
class Plot_XY(PlotData):
"""Subclass for for plotting X-Y relations of data"""
def __test__(initdata):
assert Data_is_the_right_kind
Plot_XY.register()
This works, but seems like a very dirty solution to me - a very important part of the class structure is located outside of the body.
Another possibility could be class decorators. However, I've never used them before, and the examples I've found are generally used to override/add functionality to methods. ( here和here中显示文字。我对函数装饰器很熟悉,以下内容应该大致说明我的目标(以及一个愚蠢的版本在解释器中起作用):
def some_creative_decorator_name(cls):
cls.register()
return cls
或者至少是像解决方案1一样起作用的东西,但看起来像是:
@some_creative_decorator_name
class Plot_XY(PlotData):
"""Subclass for for plotting X-Y relations of data"""
def __test__(initdata):
assert Data_is_the_right_kind
它似乎同样有效,但这会搞砸继承这样的东西吗?这是链接页面中提到的问题之一,我真的不敢指望它。 (我不希望人们进一步细分它,但如果需要的话,我真的不想让它变得不可能。)
(当然也欢迎其他解决方案。)
答案 0 :(得分:6)
你所做的事情是无用的,因为它已经提供了:
>>> class A(object):pass
...
>>> class B(A):pass
...
>>> class C(A): pass
...
>>> A.__subclasses__()
[<class '__main__.B'>, <class '__main__.C'>]
>>>
当python已经为你提供一个时,没有必要保留自己的subclasslist
。
请注意,这不包括子类的子类:
>>> class D(B):pass
...
>>> A.__subclasses__()
[<class '__main__.B'>, <class '__main__.C'>]
然而,找到所有子类很容易:
>>> def all_subclasses(klass):
... for sub in klass.__subclasses__():
... yield sub
... yield from all_subclasses(sub)
...
>>> list(all_subclasses(A))
[<class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>]
这就是说,如果要复制此功能,则更容易查看默认方法的工作原理。你会发现:
>>> '__subclasses__' in dir(object)
False
>>> '__subclasses__' in dir(type)
True
所以在这里你可以看到它是type
的方法,它是object
的元类。正确复制它的方法是编写自定义元类。
基本上,元类与装饰器方法类似:
我不会在这里详述。有关元类的更多信息,请查看What is a metaclass in Python?。