如何在继承链中创建嵌套的 __init__ 函数?
How to create nested __init__ functions in a inheritance chain?
我正在尝试实现继承系统,其中 child class 会向他从 ansister 那里收到的字典添加一个值。
例如:
class First:
specificator = {'first':1}
inherited_specificator = {}
def __init__(self, *args, **kwargs):
???
class Second(First):
specificator = {'second':2}
class Third(Second):
specificator = {'third':3}
所以我希望我可以实现第三个 class 实例的初始化方法 inherited_specificator = {'first':1, 'second':2, 'third':3}
我尝试过的:
创建将要调用的 init 方法 parent 将要调用的 init 方法...等等,以收集来自所有顶级 classes.
的说明符
class First:
specificator = {'first':1}
def __init__(self, *args, **kwargs):
super().__init__(args, kwargs)
if not getattr(self, 'inherited_specificator ', None): setattr(self, 'inherited_specificator', {})
self.inherited_specificator = {**self.inherited_specificator , **self.specificator}
但是由于某种原因它对我不起作用,Third().inherited_specificator 等于 {'third':3}。也许我不完全理解 super() 方法的工作方式,但我无法找到有关我的案例的详细信息。
我还尝试创建 set_specificator 函数,该函数将从 init 调用,并且应该在其中将当前 class 说明符添加到继承的说明符,但出现了同样的问题,我得到的只是 {'third':3}.
我的情况有解决办法吗?提前致谢。
更新:
如果可能的话,我正在寻找不覆盖 init 方法的解决方案
看来这就是你想要的:
class First:
def __init__(self):
self.specificator = {'first':1}
class Second(First):
def __init__(self):
super().__init__()
self.specificator['second'] = 2
class Third(Second):
def __init__(self):
super().__init__()
self.specificator['third'] = 3
然后就是输出:
> f = First()
> s = Second()
> t = Third()
> f.specificator
{'first': 1}
> s.specificator
{'first': 1, 'second': 2}
> t.specificator
{'first': 1, 'second': 2, 'third': 3}
请注意,不必按此顺序执行此操作;我只是为了演示而做的。你仍然可以这样做:
> t = Third()
> t.specificator
{'first': 1, 'second': 2, 'third': 3}
包括参数的继承,隔离在一个inherited_specificator
:
from copy import copy
class First:
def __init__(self, *args, **kwargs):
print(" > called First.__init__()")
self.specificator = {"first": 1}
print("specificator: %s" % self.specificator)
print(" < end First.__init__()")
class Second(First):
def __init__(self, *args, **kwargs):
print(" > called Second.__init__()")
super().__init__(self)
self.inherited_specificator = copy(self.specificator)
self.specificator["second"] = 2
print("inherited_specificator: %s" % self.inherited_specificator)
print("specificator: %s" % self.specificator)
print(" < end Second.__init__()")
class Third(Second):
def __init__(self, *args, **kwargs):
print(" > called Third.__init__()")
super().__init__(self)
self.inherited_specificator.update(self.specificator)
self.specificator = {"third": 3}
print("inherited_specificator: %s" % self.inherited_specificator)
print("specificator: %s" % self.specificator)
print(" < end Third.__init__()")
obj = Third()
给出输出:
> called Third.__init__()
> called Second.__init__()
> called First.__init__()
specificator: {'first': 1}
< end First.__init__()
inherited_specificator: {'first': 1}
specificator: {'first': 1, 'second': 2}
< end Second.__init__()
inherited_specificator: {'first': 1, 'second': 2}
specificator: {'third': 3}
< end Third.__init__()
您可以遍历方法解析顺序 (MRO),检查每个 class 是否有可用于更新 inherited_specificator
的 specificator
属性。您可能希望以相反的顺序进行迭代,以便子 classes 可以覆盖继承的值。
class First:
specificator = {'first':1}
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.inherited_specificator = {}
for s in reversed(type(self).mro()):
try:
self.inherited_specificator.update(s.specificator)
except AttributeError:
pass
class Second(First):
specificator = {'second':2}
class Third(Second):
specificator = {'third':3}
t = Third()
print(t.inherited_specificator)
MRO 的这种手动遍历是必要的,因为每个实例只会调用一个 __init__
。该调用只会看到传递给该调用的实际实例的 specificator
属性:没有 First
和 Second
的“中间”实例将在其上调用 First.__init__
在 Third
的实际实例传递给 First.__init__
.
之前
或者,您可以使 inherited_specificator
成为 class 属性(在我看来这更有意义)而不是实例属性,并使用 __init_subclass__
定义它(当class 是定义的,而不是在实例化时定义的。
class Specification:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.inherited_specificator = \
getattr(cls, 'inherited_specificator', {})\
| getattr(cls, 'specificator', {})
class First(Specification):
specificator = {'first':1}
class Second(First):
specificator = {'second':2}
class Third(Second):
specificator = {'third':3}
这里的关键是我们(尝试)在创建新的 class 自己的值之前访问 inherited_specificator
的继承值,这将是继承值和class 的 specificator
属性的值(如果已定义)。
我正在使用 Python 3.9 中引入的新字典合并运算符。在早期版本中,使用类似
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
inherited = getattr(cls, 'inherited_specificator', {})
d = cls.inherited_specificator = {}
new_values = getattr(cls, 'specificator', {})
d.update(**inherited, **new_values)
我正在尝试实现继承系统,其中 child class 会向他从 ansister 那里收到的字典添加一个值。
例如:
class First:
specificator = {'first':1}
inherited_specificator = {}
def __init__(self, *args, **kwargs):
???
class Second(First):
specificator = {'second':2}
class Third(Second):
specificator = {'third':3}
所以我希望我可以实现第三个 class 实例的初始化方法 inherited_specificator = {'first':1, 'second':2, 'third':3}
我尝试过的:
创建将要调用的 init 方法 parent 将要调用的 init 方法...等等,以收集来自所有顶级 classes.
的说明符class First:
specificator = {'first':1}
def __init__(self, *args, **kwargs):
super().__init__(args, kwargs)
if not getattr(self, 'inherited_specificator ', None): setattr(self, 'inherited_specificator', {})
self.inherited_specificator = {**self.inherited_specificator , **self.specificator}
但是由于某种原因它对我不起作用,Third().inherited_specificator 等于 {'third':3}。也许我不完全理解 super() 方法的工作方式,但我无法找到有关我的案例的详细信息。
我还尝试创建 set_specificator 函数,该函数将从 init 调用,并且应该在其中将当前 class 说明符添加到继承的说明符,但出现了同样的问题,我得到的只是 {'third':3}.
我的情况有解决办法吗?提前致谢。
更新:
如果可能的话,我正在寻找不覆盖 init 方法的解决方案
看来这就是你想要的:
class First:
def __init__(self):
self.specificator = {'first':1}
class Second(First):
def __init__(self):
super().__init__()
self.specificator['second'] = 2
class Third(Second):
def __init__(self):
super().__init__()
self.specificator['third'] = 3
然后就是输出:
> f = First()
> s = Second()
> t = Third()
> f.specificator
{'first': 1}
> s.specificator
{'first': 1, 'second': 2}
> t.specificator
{'first': 1, 'second': 2, 'third': 3}
请注意,不必按此顺序执行此操作;我只是为了演示而做的。你仍然可以这样做:
> t = Third()
> t.specificator
{'first': 1, 'second': 2, 'third': 3}
包括参数的继承,隔离在一个inherited_specificator
:
from copy import copy
class First:
def __init__(self, *args, **kwargs):
print(" > called First.__init__()")
self.specificator = {"first": 1}
print("specificator: %s" % self.specificator)
print(" < end First.__init__()")
class Second(First):
def __init__(self, *args, **kwargs):
print(" > called Second.__init__()")
super().__init__(self)
self.inherited_specificator = copy(self.specificator)
self.specificator["second"] = 2
print("inherited_specificator: %s" % self.inherited_specificator)
print("specificator: %s" % self.specificator)
print(" < end Second.__init__()")
class Third(Second):
def __init__(self, *args, **kwargs):
print(" > called Third.__init__()")
super().__init__(self)
self.inherited_specificator.update(self.specificator)
self.specificator = {"third": 3}
print("inherited_specificator: %s" % self.inherited_specificator)
print("specificator: %s" % self.specificator)
print(" < end Third.__init__()")
obj = Third()
给出输出:
> called Third.__init__()
> called Second.__init__()
> called First.__init__()
specificator: {'first': 1}
< end First.__init__()
inherited_specificator: {'first': 1}
specificator: {'first': 1, 'second': 2}
< end Second.__init__()
inherited_specificator: {'first': 1, 'second': 2}
specificator: {'third': 3}
< end Third.__init__()
您可以遍历方法解析顺序 (MRO),检查每个 class 是否有可用于更新 inherited_specificator
的 specificator
属性。您可能希望以相反的顺序进行迭代,以便子 classes 可以覆盖继承的值。
class First:
specificator = {'first':1}
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.inherited_specificator = {}
for s in reversed(type(self).mro()):
try:
self.inherited_specificator.update(s.specificator)
except AttributeError:
pass
class Second(First):
specificator = {'second':2}
class Third(Second):
specificator = {'third':3}
t = Third()
print(t.inherited_specificator)
MRO 的这种手动遍历是必要的,因为每个实例只会调用一个 __init__
。该调用只会看到传递给该调用的实际实例的 specificator
属性:没有 First
和 Second
的“中间”实例将在其上调用 First.__init__
在 Third
的实际实例传递给 First.__init__
.
或者,您可以使 inherited_specificator
成为 class 属性(在我看来这更有意义)而不是实例属性,并使用 __init_subclass__
定义它(当class 是定义的,而不是在实例化时定义的。
class Specification:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.inherited_specificator = \
getattr(cls, 'inherited_specificator', {})\
| getattr(cls, 'specificator', {})
class First(Specification):
specificator = {'first':1}
class Second(First):
specificator = {'second':2}
class Third(Second):
specificator = {'third':3}
这里的关键是我们(尝试)在创建新的 class 自己的值之前访问 inherited_specificator
的继承值,这将是继承值和class 的 specificator
属性的值(如果已定义)。
我正在使用 Python 3.9 中引入的新字典合并运算符。在早期版本中,使用类似
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
inherited = getattr(cls, 'inherited_specificator', {})
d = cls.inherited_specificator = {}
new_values = getattr(cls, 'specificator', {})
d.update(**inherited, **new_values)