gpt4 book ai didi

python - 基类中派生类的范围-python中的继承

转载 作者:行者123 更新时间:2023-12-01 00:19:57 24 4
gpt4 key购买 nike

我知道通过继承基类。基类中的所有函数也可以在派生类中访问。但是它如何以另一种方式工作,这意味着在子类中定义的函数可以在基类中访问。

我用一个例子尝试了上述方法。它工作得很好。但这怎么可能。我无法理解工作背后的逻辑。

class fish:

def color(self):
# _colour is a property of the child class. How can base class access this?
return self._colour


class catfish(fish):

_colour = "Blue Cat fish"

def speed(self):
return "Around 100mph"

def agility(self):
return "Low on the agility"

class tunafish(fish):

_colour = "Yellow Tuna fish"

def speed(self):
return "Around 290mph"

def agility(self):
return "High on the agility"

catfish_obj = catfish()
tunafish_obj = tunafish()

print(catfish_obj.color())
print(tunafish_obj.color())

我知道实例是通过 self 传递的,但是子类的细节在逻辑上不应该在基类中访问,对吗?!

最佳答案

您正在访问实例上的属性,不在类里面 .您的 self reference 永远不是 fish 的实例类,仅属于两个派生类之一,并且那些派生类设置 _colour属性。

如果您创建了 fish() 的实例本身,您会收到属性错误,因为该实例将没有设置属性。

你可能会认为在基类中,self成为基类的实例;事实并非如此。

相反,实例上的属性直接在实例上查找,并在其类和基类上查找。所以self._colour查看实例,位于 type(instance)以及 type(instance).__mro__ 中的所有其他对象,方法解析顺序,它以线性顺序设置层次结构中的所有类。

您可以打印出 type()你的对象:

>>> class fish:
... def color(self):
... print(type(self))
... return self._colour
...
# your other class definitions
>>> print(catfish_obj.color())
<class '__main__.catfish'>
Blue Cat fish
>>> print(tunafish_obj.color())
<class '__main__.tunafish'>
Yellow Tuna fish
self引用是派生类的实例,传递给继承的方法。所以 self._colour先看 self上直接设置的属性,然后在 type(self) , 还有 _colour被发现。

也许了解 Python 方法的工作原理会有所帮助。方法只是函数的薄包装,在您查找实例的属性时创建:
>>> tunafish_obj.color  # access the method but not calling it
<bound method fish.color of <__main__.tunafish object at 0x110ba5278>>
>>> tunafish.color # same attribute name, but on the class
<function fish.color at 0x110ba3510>
>>> tunafish.color.__get__(tunafish_obj, tunafish) # what tunafish_obj.color actually does
<bound method fish.color of <__main__.tunafish object at 0x110ba5278>>
>>> tunafish_obj.color.__self__ # methods have attributes like __self__
<__main__.tunafish object at 0x110ba5278>
>>> tunafish_obj.color.__func__ # and __func__. Recognise the numbers?
<function fish.color at 0x110ba3510>

仔细查看我访问的对象的名称,以及当我调用 __get__ 时会发生什么函数上的方法。当您访问实例上的某些属性时,Python 使用称为绑定(bind)的过程;当您以这种方式访问​​属性时,它指向具有 __get__ 的对象方法,则该对象称为描述符, __get__被调用以将对象绑定(bind)到您查找对象的任何内容。见 descriptor howto .

访问 color在实例上,产生一个绑定(bind)的方法对象,但对象的描述告诉我们它来自 fish ,它被命名为 *bound 方法 fish.color实例引用。在类上访问相同的名称会给我们 fish.color函数,我可以手动绑定(bind)它再次创建一个方法。

最后,该方法有一个属性 __self__ ,这是原始实例, __func__这是原始功能。神奇的是,当你调用绑定(bind)方法时,方法对象只调用 __func__(__self__, ....) ,所以传入它绑定(bind)的实例。

当该函数被继承时,(在 fish 类中找到,所以 fish.color ),它仍然被传递一个派生类的实例,并且仍然具有派生类的所有内容。

Python 非常动态,而且非常灵活。您可以将任何旧函数放在一个类中,并且可以将它绑定(bind)到一个方法中。或者,您可以采用任何未绑定(bind)的函数,并手动传入具有正确属性的对象,然后它就可以工作了。 Python 不在乎,真的。所以你可以传入一个新的、独立类型的对象并且仍然拥有 fish.color功能工作:
>>> fish.color  # original, unbound function on the base class
<function fish.color at 0x110ba3510>
>>> class FakeFish:
... _colour = 'Fake!'
...
>>> fish.color(FakeFish) # passing in a class! Uh-oh?
<class 'type'>
'Fake!'

所以即使传入一个类对象,与 fish 完全无关层次结构,但具有预期的属性,仍然有效。

对于大多数 Python 代码来说,如果它像鸭子一样走路,像鸭子一样嘎嘎叫,那么代码会接受它作为鸭子。调用 duck typing .

关于python - 基类中派生类的范围-python中的继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49466372/

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