[英]Scope of derived class in base class - Inheritance in python
我知道通過繼承基類。 基類中的所有功能也可以在派生類中訪問。 但是它是如何工作的,這意味着可以在基類中訪問子類中定義的函數。
我用一個例子嘗試了上面。 而且效果很好。 但是那怎么可能。 我無法理解工作背后的邏輯。
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
引用絕不會是fish
類的實例,只能是兩個派生類之一的實例,而這些派生類將設置_colour
屬性。
如果您自己創建了fish()
的實例,則會出現屬性錯誤,因為該實例將沒有設置屬性。
您可能會認為,在基類中, self
成為基類的一個實例。 事實並非如此。
相反,在實例屬性的情況下直接查找, 並於它的類和基類。 因此self._colour
查看實例, type(instance)
以及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使用稱為綁定的過程。 當您以這種方式訪問屬性並使用__get__
方法指向一個對象時,該對象稱為描述符 ,並且__get__
將該對象綁定到您在對象上查找的對象。 參見描述符howto 。
訪問實例上的color
會生成一個綁定方法對象,但是該對象的描述告訴我們它來自fish
,它被稱為* instance reference的* bound方法fish.color
。 在類上訪問相同的名稱會給我們fish.color
函數 ,我可以手動將其綁定以再次創建一個方法。
最后,該方法具有屬性__self__
,這是原始實例,並且__func__
這是原始功能。 神奇的是,當您調用綁定方法時,方法對象僅調用__func__(__self__, ....)
,因此傳入綁定到的實例。
繼承該函數(在fish
類上找到,即fish.color
)后,該函數仍將傳遞派生類的實例 ,並且仍然具有派生類擁有的所有內容。
Python非常動態,而且非常靈活。 您可以采用任何舊函數並將其放在類上,並且可以將其綁定到方法中。 或者,您可以采用任何未綁定的函數,然后手動傳遞具有正確屬性的對象,它就會正常工作 。 真的,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代碼而言,如果它走路像鴨子,而嘎嘎叫鴨子,則代碼會將其接受為鴨子。 稱它為鴨子打字 。
派生類的方法在基類中不可用。 但是,這些字段對於在特定對象上運行的任何功能都是共享的。 self._colour
指的是您要在其上調用color()
的對象中_colour
的值,而不管如何設置_colour
。
編輯因為你設置_colour = ...
直接在類,函數外,任何catfish
都會有_colour == "Blue Cat fish"
和任何tunafish
將有_colour == "Yellow Tuna fish"
。 這些值盡管在類上設置,但在每個實例中都可用。 這就是為什么即使您從未直接說過self._colour = ...
self._colour
起作用的原因。 如果您想具體魚的顏色,你就需要設置self._colour
在catfish.__init__
或tunafish.__init__
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.