gpt4 book ai didi

python:继承类中的连续 __getitem__() 调用?

转载 作者:太空宇宙 更新时间:2023-11-04 00:52:54 24 4
gpt4 key购买 nike

我遇到了一个我不明白的问题,而且它很复杂,所以我尽力在这里分解它。请看下面的实现。我的问题是:为什么父类调用它的子类的 __getitem__ 方法,而不是调用它自己的 __getitem__?

class Father(object):
''' Father class '''
def __init__(self,name,gender):
print('call __init__ Father')
self._name = name
# trying to call Father's __getitem__ here
self._gender=self[gender]

def __getitem__(self,key):
print('call __getitem__ Father')
return key

class Child(Father):
''' inherited from Father class '''
def __init__(self, name, gender, age=None):
print('call __init__ Child')
super(self.__class__, self).__init__(name, gender)
self._age = age

def __getitem__(self, key):
print('call __getitem__ Child')
if self._name == 'Marie' and self._age == None:
print('I am not sure, how old I am')
return super(self.__class__, self).__getitem__(key)

one=Child('Klaus','male','12')
other=Child('Marie','female')

将出现的错误信息是:

call __init__ Child
call __init__ Father
call __getitem__ Child
call __getitem__ Father
call __init__ Child
call __init__ Father
call __getitem__ Child
Traceback (most recent call last):

File "<ipython-input-58-2d97b09f6e25>", line 1, in <module>
runfile('F:/python-workspace/more-fancy-getitem-fix/test.py', wdir='F:/python-workspace/more-fancy-getitem-fix')

File "C:\Python27\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 601, in runfile
execfile(filename, namespace)

File "C:\Python27\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 66, in execfile
exec(compile(scripttext, filename, 'exec'), glob, loc)

File "F:/python-workspace/more-fancy-getitem-fix/test.py", line 26, in <module>
other=Child('Marie','female')

File "F:/python-workspace/more-fancy-getitem-fix/test.py", line 16, in __init__
super(self.__class__, self).__init__(name, gender)

File "F:/python-workspace/more-fancy-getitem-fix/test.py", line 6, in __init__
self._gender=self[gender]

File "F:/python-workspace/more-fancy-getitem-fix/test.py", line 21, in __getitem__
if self._name == 'Marie' and self._age == None:

AttributeError: 'Child' object has no attribute '_age'

我不希望有这种行为。我试图从 Father 继承 Child 添加功能,因此上述所有语法都是必要的,并且在我更复杂的代码中有意义。one=Child('Klaus','male','12') 的第一个示例运行顺利,我们已经可以看到,在父亲的构造函数中调用了 child 的 __getitem__ 。在 other=Child('Marie','female') 的第二个示例中,可以看出为什么这种反向调用让我感到困扰。这里的代码在定义 self._age = age 之前不会运行。

除了建议这个反之亦然的调用可能如何有用以及它的目的,我将非常感谢如何在父亲中显式调用自己的 __getitem__ 方法的解决方案。刚写完

self._gender=self.__getitem__(gender) #instead of
self._gender=self[gender]

不幸的是,它没有成功并产生同样的错误。

最佳答案

要修复,只需交换 Child __init__ 中的初始化顺序,以便 Child.__getitem__< 所需的 Child 属性 在需要之前被初始化:

def __init__(self, name, gender, age=None):
print('call __init__ Child')
self._age = age
super(Child, self).__init__(name, gender)

这个修复是这个特定场景所独有的,但它通常也是正确的修复;通常,父类的唯一责任是尽量不要不必要地破坏子类化,但不能指望他们为子类计划创建新的类不变量并尝试提前容纳它们。子类应该完全了解父类,子类有责任确保它不会破坏父类的任何行为,在这种情况下,通过确保在父类之前定义所有新的必需属性可能会使用需要它们的方法。

至于为什么它会调用子类的 __getitem__,这就是默认情况下子类化的工作方式(不仅在 Python 中,而且在大多数 OO 语言中)。 Father.__init__Child.__init__ 接收到的 self 仍然是一个 Child 对象,因此查找检查 __getitem__ 首先在 Child 上。如果没有,您会产生令人困惑的行为,其中 Child 上的一些索引调用了 __getitem__ 而有些则没有,这会使它变得非常不直观。

如果出于某种原因你绝对必须在 Father.__init__ 中只使用 Father__getitem__,你只需要明确说明你调用的方法。代替 self[gender]self.__getitem__(gender)(两者都通过正常的查找过程),执行 Father.__getitem__(self, gender) 显式调用方法的 Father 版本(并且还要求您显式传递 self,因为您使用的是未绑定(bind)方法而不是绑定(bind)方法).

另一种方法是定义一个指示实例未完全初始化的属性,并在父初始化器期间绕过子重载,以便在初始化期间调用父方法:

def __init__(self, name, gender, age=None):
print('call __init__ Child')
# Use double underscore prefix to make a private attribute of Child
# not directly visible to parent or lower level children so no risk
# of being reused by accident
self.__in_parent_init = True
super(Child, self).__init__(name, gender)
self.__in_parent_init = False
self._age = age

def __getitem__(self, key):
if self.__in_parent_init:
# Don't use Child specific features until Father initialized
return super(Child, self).__getitem__(key)
print('call __getitem__ Child')
if self._name == 'Marie' and self._age == None:
print('I am not sure, how old I am')
return super(Child, self).__getitem__(key)

关于python:继承类中的连续 __getitem__() 调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36439150/

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