我遇到了一个我不理解的问题,它相当复杂,所以我尽力在这里把它分解。请看一下下面的实现。我的问题是:为什么父类调用其子类的\uugetitem\uu方法,而不是调用自己的?在
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')
将出现的错误消息是:
^{pr2}$我不会料到会有这种行为。我试图从父亲那里继承Child并添加功能,所以上面所有的语法都是必要的,在我更复杂的代码中也是有意义的。 one=Child('Klaus','male','12')的第一个示例运行得很顺利,我们已经可以看到,在父构造函数中,子元素的\uugetitem_Uu被调用了。 在other=Child('Marie','female')的第二个例子中,我们可以理解为什么这个反向调用会困扰我。在这里,只有在定义self.\u age=age时,代码才会运行。在
从建议这个相反的调用如何有用以及它的目的,我将非常感谢如何显式地调用父中的自己的getitem_Uu方法的解决方案。只是写作
self._gender=self.__getitem__(gender) #instead of
self._gender=self[gender]
不幸的是,它没有做到这一点,并产生同样的错误。在
这里使用的
^{pr2}$__getitem__
方法将通过self
的实际类查找。如果self
是Child
的实例,它将使用Child.__getitem__
。您可以将其更改为显式使用Father.__getitem__
:虽然你的整体设计还是有点混乱,而且可能会导致更多的问题。在
无关但重要:
永远不要这样做。如果在任何一个类中这样做的话,它就会中断。必须显式地提供类名。在
要修复此问题,只需交换
Child
__init__
中的初始化顺序,这样Child.__getitem__
所需的Child
属性在需要之前被初始化:这个修复对于这个特定的场景是唯一的,但是它通常也是正确的修复;一般来说,父类的唯一责任是不要不必要地中断子类化,但是不能期望它们计划让子类创建新的类不变量,并尝试预先适应它们。子类应该完全了解父类,子类的责任是确保它不会破坏父类的任何行为,在这种情况下,通过确保在父类可能使用需要它们的方法之前定义了所有新的必需属性。在
至于它为什么调用子类的
__getitem__
,这就是子类化的默认工作方式(不仅在Python中,而且在大多数OO语言中)。Father.__init__
从Child.__init__
接收的self
仍然是Child
对象,因此查找首先检查Child
上的__getitem__
。如果不这样做,您将有混乱的行为,其中一些索引在Child
上调用__getitem__
而有些没有,这将使它非常不直观。在如果出于某种原因,您绝对必须在
Father.__init__
中只使用Father
的__getitem__
,那么您只需要明确您调用的是哪个方法。不要使用self[gender]
或self.__getitem__(gender)
(这两种方法都要经过正常的查找过程),doFather.__getitem__(self, gender)
显式调用方法的Father
版本(还需要显式地传递self
,因为您使用的是未绑定方法而不是绑定方法)。在在初始化过程中,父方法和子方法将不会被完全调用,因此在初始化过程中不会完全调用父方法:
^{pr2}$相关问题 更多 >
编程相关推荐