簡體   English   中英

基類中派生類的范圍-python中的繼承

[英]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._colourcatfish.__init__tunafish.__init__

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM