2015-09-22 93 views
3

我想了解繼承如何在Python中工作。我正在看一個簡單的代碼,有一件事讓我感到困惑。代碼如下:Python中的繼承基礎知識

class Person: 

    def __init__(self, first, last): 
     self.firstname = first 
     self.lastname = last 

    def Name(self): 
     return self.firstname + " " + self.lastname 

class Employee(Person): 

    def __init__(self, first, last, staffnum): 
     Person.__init__(self,first, last) 
     self.staffnumber = staffnum 

    def GetEmployee(self): 
     return self.Name() + ", " + self.staffnumber 

x = Person("Marge", "Simpson") 
y = Employee("Homer", "Simpson","1007") 
print(x.Name()) 
print(y.GetEmployee()) 

我的問題是,在再次使用時Person.__init__()調用基類的構造函數,但是當我們調用名稱()基類的方法,而不是使用「人」,我們使用「自」。有人可以澄清這種困惑,我瞭解Python的繼承是如何工作的?

+3

這不是很pythonic的代碼,可能不是最好的學習!但是請注意,只有當子類沒有實現'method' **時,纔可以使用'self.method'來訪問超類實現**。這裏的子類實現了'__init__',所以需要明確地訪問超類的版本(雖然它應該用'super'來實現),但是不實現'Name'。嘗試改變它,看看會發生什麼! – jonrsharpe

+0

還有一個問題,當我們需要調用一個父類的方法時,我們需要傳遞孩子(自我)作爲參數。爲什麼? –

+0

因爲你沒有使用'super(Employee,self).__ init __(first,last)'。搜索綁定與未綁定方法的信息; 'self.Name'被綁定,'Person .__ init__'被解除綁定。 – jonrsharpe

回答

1

以下兩種方法是等效的(假設「名稱」方法不會被覆蓋):

class Employee(Person): 
    def __init__(self, first, last, staffnum): 
     Person.__init__(self, first, last) 
     self.staffnumber = staffnum 

    def getEmployee(self): 
     return Person.Name(self) + self.staffnumber 


class Employee(Person): 
    def __init__(self, first, last, staffnum): 
     Person.__init__(self, first, last) 
     self.staffnumber = staffnum 

    def getEmployee(self): 
     return self.Name() + self.staffnumber 

在第二個例子中,當self.Name()被調用時,類的實例是「綁定「的功能,所以第一個參數不需要傳遞。

因爲init在Employee子類中被覆蓋,所以不能調用self。 init(first,last)。然後你會打電話給員工。 init(self,* args)而不是Person。 init(self,* args)。這將創建一個無限遞歸循環,否則你會得到一個參數錯誤。

作爲一般規則,當您重寫某個方法時,必須在子類中使用以下表示法。 ParentClass.methodname(self,* args,** kwargs)。你可以調用self.Name()的原因是因爲名字沒有被覆蓋。

我在這裏重複自己。這會使它結晶嗎?還是讓我更加困惑?

+0

我不確定這會回答這個問題,因爲它不能解釋'__init__'和'Name'之間調用的區別。 – jonrsharpe

+0

它被綁定到函數意味着它繼承了方法Name(),所以它也可以被self.Name()調用?如果那是真的,那我就明白了。其次,爲什麼我們需要將自己作爲一個參數來傳遞,那就是把孩子傳遞給父類? –

2

Employee類繼承了基類Person類的方法,其中包括__init__方法。所以在類定義的頂部,它有__init__Name方法。

然後Employee類定義將覆蓋它繼承的方法__init__。爲了調用Person__init__方法,它必須按名稱調用Person.__init__(實際上,它可以使用super()作爲另一種選擇)。

但由於Employee不會覆蓋繼承Name方法,它可以使用self.Name()調用Name方法,它繼承了頂部。

+0

非常感謝你!得到它了!! :) –

+0

還有一個問題,當我們需要調用父類的方法時,我們需要傳遞子(self)作爲參數。爲什麼? –

0

說簡單的說法就是self.method()的意思是「調用method可用的最具體的實現」(即,當前對象的繼承樹最遠的那個)。在這種情況下,您不必撥打電話self.__init__,因爲這會再次調用Employee.__init__。您需要編寫Person.__init__(或使用super())來顯式調用繼承的方法。

因爲Employee沒有定義自己的Name方法,Person.Name是可用的最具體的一個,所以這就是被稱爲self.Name()。如果Employee定義了它自己的Name,那麼將由self.Name()來代替。

+0

非常感謝你!我現在明白了! :) :) –

+0

還有一個問題,當我們需要調用父類的方法時,我們需要傳遞子(self)作爲參數。爲什麼? –

+0

@ShahrozPunjwani:每當你在一個類上調用一個方法時(如在Person.__ init__中),你需要傳遞該實例作爲第一個參數。當你調用實例的方法時(如'self.Name'),你不會(它會自動爲你傳遞)。 – BrenBarn