gpt4 book ai didi

python - 调用类方法作为初始化的一部分

转载 作者:太空狗 更新时间:2023-10-30 01:00:13 24 4
gpt4 key购买 nike

现状

我有一个抽象基类,它以 numpy 数组的形式承载数据,知道如何处理这些数据,并且可以解释 matplotlib 如何绘制它。为了适应不同类型的数据,它有许多子类,如下所示:

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

问题

现在,问题是如何将类引用放入子类列表中。起初我想在类主体中调用 super().register(),但我无法获得对类本身的引用,这是我想存储在列表中的内容。一个小的搜索产生了两种可能的解决方案,我想知道最好的是什么。

解决方案1

在每个类定义之后添加一个调用,如下所示:

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()

这可行,但对我来说似乎是一个非常肮脏的解决方案——类结构的一个非常重要的部分位于主体之外。

解决方案2

另一种可能性是类装饰器。但是,我以前从未使用过它们,而且我发现的示例通常用于覆盖/向方法添加功能。 (例如 herehere)。不过,我对函数装饰器很熟悉,下面应该大致说明我的目标是什么(并且在解释器中有一个简化的版本):

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

它似乎也能正常工作,但这会搞砸继承之类的东西吗?这是链接页面中提到的问题之一,我真的不敢指望它。 (我不希望人们进一步对它进行子类化,但如果需要的话,我真的不想让它变得不可能。)

(当然也欢迎其他解决方案。)

最佳答案

你正在做的是无用的,因为它已经提供了:

>>> 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的一个方法,它是objectmetaclass。正确复制它的方法是编写您的自定义元类。

元类基本上类似于装饰器方法:

  • 它更通用,因为您可以在创建类之前做一些事情,控制它的创建方式并在之后做一些事情。装饰器在完成时接收类对象,只能做创建后的事情
  • 它们是继承的,因此您不必为每个类显式添加任何内容,而只需添加到基类即可。

这里我就不多说了。查看What is a metaclass in Python?有关元类的更多信息。

关于python - 调用类方法作为初始化的一部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36719164/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com