首頁  >  文章  >  後端開發  >  Python物件導向程式設計(二)

Python物件導向程式設計(二)

PHP中文网
PHP中文网原創
2017-07-09 18:13:531252瀏覽

1.繼承與派生

上文我們已經說過,Python中一切皆對象。我們從物件中抽取了共同特徵和技能,得到了類別的概念。類別與類別之間也有共同特徵,我們可以從有共同特徵和技能的類別中提取共同的技能和特徵,稱為父類。

例如老師和學生,都有名字,年紀,生日,性別等等,都會走,說話,吃飯。 。 。我們就可以從老師和學生中總結出來一個‘人’類,稱為父類,那老師和學生就是‘人’類的子類,子類繼承父類,就有了父類的特徵和方法。

繼承是一種什麼『是』什麼的關係,繼承是一種產生新類別的方法,當然目的也是為了減少程式碼重用。

繼承的 基本形式是:

<span style="color: #0000ff">class</span><span style="color: #000000"> People:
    </span><span style="color: #0000ff">pass</span>
<span style="color: #0000ff">class</span> Student(People):<span style="color: #008000">#</span><span style="color: #008000">People称为基类或者父类</span>
    <span style="color: #0000ff">pass</span>

在Python中支援多繼承,一個子類別可以繼承多個父類別

我們可以透過__bases__的方法查看繼承的所有父類,會傳回一個元組。 

<span style="color: #0000ff">class</span><span style="color: #000000"> People:
    </span><span style="color: #0000ff">pass</span>
<span style="color: #0000ff">class</span><span style="color: #000000"> Animals:
    </span><span style="color: #0000ff">pass</span>
<span style="color: #0000ff">class</span><span style="color: #000000"> Student(People,Animals):
    </span><span style="color: #0000ff">pass</span>

<span style="color: #0000ff">print</span>(Student.<span style="color: #800080">__bases__</span>)<span style="color: #008000">#</span><span style="color: #008000">(<class '__main__.People'>, <class '__main__.Animals'>)</span>
<span style="color: #0000ff">print</span>(People.<span style="color: #800080">__bases__</span>)<span style="color: #008000">#</span><span style="color: #008000">(<class 'object'>,)</span>

可以看到,在People父類中,預設也繼承了一個object類,這就是新式類別和經典類別的區別:
凡是繼承了object類別的類別及其子類,都稱為新式類,沒有繼承object類的類,稱為經典類。

在Python 3中,預設就是新式類,而在Python2.X中,預設都是是經典類別

繼承怎麼減少程式碼呢?看例子

<span style="color: #0000ff">class</span><span style="color: #000000"> People:
    </span><span style="color: #0000ff">def</span> <span style="color: #800080">__init__</span><span style="color: #000000">(self,name,age):
        self.name</span>=<span style="color: #000000">name
        self.age</span>=<span style="color: #000000">age
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> walk(self):
        </span><span style="color: #0000ff">print</span>(<span style="color: #800000">'</span><span style="color: #800000">%s is walkig</span><span style="color: #800000">'</span>%<span style="color: #000000">self.name)

</span><span style="color: #0000ff">class</span><span style="color: #000000"> Teacher(People):
    </span><span style="color: #0000ff">def</span> <span style="color: #800080">__init__</span><span style="color: #000000">(self,name,age,level):
        People.</span><span style="color: #800080">__init__</span><span style="color: #000000">(self,name,age)
        self.level</span>=<span style="color: #000000">level

t1</span>=Teacher(<span style="color: #800000">'</span><span style="color: #800000">zhang</span><span style="color: #800000">'</span>,18,10<span style="color: #000000">)
</span><span style="color: #0000ff">print</span>(t1.level) <span style="color: #008000">#</span><span style="color: #008000">10</span>
<span style="color: #0000ff">print</span>(t1.name)  <span style="color: #008000">#</span><span style="color: #008000">zhang          子类可以用父类定义的属性</span>
t1.walk()   <span style="color: #008000">#</span><span style="color: #008000">zhang is walking   子类无需定义就可以用父类的方法</span>
<span style="color: #0000ff">print</span>(issubclass(Teacher,People))   <span style="color: #008000">#</span><span style="color: #008000">True查看Teacher类是不是People类的子类</span>

從上面的例子可以看到,Teacher類別繼承了父類People類,但是Teacher又有自己特有的屬性level,子類別也可以定義自己獨有的方法,甚至可以和父類別的方法重名,但是執行時會以子類別定義的為準。

這就叫做派生

2.組合

繼承是解決什麼'是'什麼的問題,那還有一種場景就是什麼有什麼,比如老師有生日,學生也有生日,生日有年月日這些屬性,如果每個類都寫的話,又是重複程式碼。但是又不能讓學生和老師繼承生日類。這時就用到了組合。 組合就是要解決什麼『有』什麼的問題。看範例

<span style="color: #0000ff">class</span><span style="color: #000000"> Date:
    </span><span style="color: #0000ff">def</span> <span style="color: #800080">__init__</span><span style="color: #000000">(self,year,mon,day):
        self.year</span>=<span style="color: #000000">year
        self.mon</span>=<span style="color: #000000">mon
        self.day</span>=<span style="color: #000000">day
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> tell_birth(self):
        </span><span style="color: #0000ff">print</span>(<span style="color: #800000">'</span><span style="color: #800000">出生于%s年%s月%s日</span><span style="color: #800000">'</span>%<span style="color: #000000">(self.year,self.mon,self.day))

</span><span style="color: #0000ff">class</span><span style="color: #000000"> Teacher:
    </span><span style="color: #0000ff">def</span> <span style="color: #800080">__init__</span><span style="color: #000000">(self,name,age,year,mon,day):
        self.name</span>=<span style="color: #000000">name
        self.age</span>=<span style="color: #000000">age
        self.birth</span>=<span style="color: #000000">Date(year,mon,day)
t</span>=Teacher(<span style="color: #800000">'</span><span style="color: #800000">egon</span><span style="color: #800000">'</span>,19,2010,10,10<span style="color: #000000">)
</span><span style="color: #0000ff">print</span>(t.birth)          <span style="color: #008000">#</span><span style="color: #008000"><__main__.Date object at 0x0000017E559380F0></span>
t.birth.tell_birth()    <span style="color: #008000">#</span><span style="color: #008000">出生于2010年10月10日</span>

什麼?嫌參數太多? *args學過吧,你高興就好

#
<span style="color: #008080"> 1</span> <span style="color: #0000ff">class</span><span style="color: #000000"> Date:
</span><span style="color: #008080"> 2</span>     <span style="color: #0000ff">def</span> <span style="color: #800080">__init__</span><span style="color: #000000">(self,year,mon,day):
</span><span style="color: #008080"> 3</span>         self.year=<span style="color: #000000">year
</span><span style="color: #008080"> 4</span>         self.mon=<span style="color: #000000">mon
</span><span style="color: #008080"> 5</span>         self.day=<span style="color: #000000">day
</span><span style="color: #008080"> 6</span>     <span style="color: #0000ff">def</span><span style="color: #000000"> tell_birth(self):
</span><span style="color: #008080"> 7</span>         <span style="color: #0000ff">print</span>(<span style="color: #800000">'</span><span style="color: #800000">出生于%s年%s月%s日</span><span style="color: #800000">'</span>%<span style="color: #000000">(self.year,self.mon,self.day))
</span><span style="color: #008080"> 8</span> 
<span style="color: #008080"> 9</span> <span style="color: #0000ff">class</span><span style="color: #000000"> Teacher:
</span><span style="color: #008080">10</span>     <span style="color: #0000ff">def</span> <span style="color: #800080">__init__</span>(self,name,age,*<span style="color: #000000">args):
</span><span style="color: #008080">11</span>         self.name=<span style="color: #000000">name
</span><span style="color: #008080">12</span>         self.age=<span style="color: #000000">age
</span><span style="color: #008080">13</span>         self.birth=Date(*<span style="color: #000000">args)
</span><span style="color: #008080">14</span> t=Teacher(<span style="color: #800000">'</span><span style="color: #800000">egon</span><span style="color: #800000">'</span>,19,2010,10,10<span style="color: #000000">)
</span><span style="color: #008080">15</span> <span style="color: #0000ff">print</span>(t.birth)          <span style="color: #008000">#</span><span style="color: #008000"><__main__.Date object at 0x0000017E559380F0></span>
<span style="color: #008080">16</span> t.birth.tell_birth()    <span style="color: #008000">#</span><span style="color: #008000">出生于2010年10月10日</span>
View Code

3.抽象類別與介面

繼承有兩種用途:1.程式碼重複使用,子類別繼承父類別的方法

        2.宣告某個子類別相容於某父類,定義一個介面類別Interface,介面類別中定義了一些介面名稱(就是函數名稱)且未實作介面的功能,子類別繼承介面類,並且實作介面中的功能

要注意的是,Python中並沒有介面的關鍵字,我們只能是模仿介面的功能
例如在Python中,一切皆文件嘛,那程式是文件,硬體是文件,文字文件也是文件,我們知道什麼叫文件呢,就是能讀能寫,那程序,文本文檔這些,都應該有讀和寫的功能,我們來模擬一下

#
<span style="color: #0000ff">class</span><span style="color: #000000"> Interface:
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> read(self):
        </span><span style="color: #0000ff">pass</span>
    <span style="color: #0000ff">def</span><span style="color: #000000"> write(self):
        </span><span style="color: #0000ff">pass</span>
    
    
<span style="color: #0000ff">class</span><span style="color: #000000"> Txt(Interface):
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> read(self):
        </span><span style="color: #0000ff">print</span>(<span style="color: #800000">'</span><span style="color: #800000">文本文档的读取方式</span><span style="color: #800000">'</span><span style="color: #000000">)
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> write(self):
        </span><span style="color: #0000ff">print</span>(<span style="color: #800000">'</span><span style="color: #800000">文本文档的写入方式</span><span style="color: #800000">'</span><span style="color: #000000">)
        
</span><span style="color: #0000ff">class</span><span style="color: #000000"> Sata(Interface):
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> read(self):
        </span><span style="color: #0000ff">print</span>(<span style="color: #800000">'</span><span style="color: #800000">硬盘文件的读取方式</span><span style="color: #800000">'</span><span style="color: #000000">)
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> write(self):
        </span><span style="color: #0000ff">print</span>(<span style="color: #800000">'</span><span style="color: #800000">硬盘文件的写入方式</span><span style="color: #800000">'</span><span style="color: #000000">)

</span><span style="color: #0000ff">class</span><span style="color: #000000"> process(Interface):
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> read(self):
        </span><span style="color: #0000ff">print</span>(<span style="color: #800000">'</span><span style="color: #800000">进程数据的读取方式</span><span style="color: #800000">'</span><span style="color: #000000">)
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> write(self):
        </span><span style="color: #0000ff">print</span>(<span style="color: #800000">'</span><span style="color: #800000">进程数据的写入方式</span><span style="color: #800000">'</span>)
View Code

这么做的意义就是:我们不需要知道子类有什么具体的方法,既然他们继承了文件类,那他们就是文件,那他们就有读和写这两个功能

父类限制了子类子类必须有read和write这两个方法,而且名字也必须一样(当然现在只是我们主观上的限制,一会我们说完抽象类,就可以从代码级别上限制了),这样就实现了统一,模拟了接口的概念,这就是归一化设计。在归一化设计中,只要是基于一个接口设计的类,那么所有的这些类实例化出来的对象,在用法上是一样的

我们再来说一下抽象类:

Python中的抽象类需要导入一个模块来实现。抽象类只能被继承,不能被实现

抽象类的写法:

<span style="color: #0000ff">import</span><span style="color: #000000"> abc
</span><span style="color: #0000ff">class</span> File(metaclass=<span style="color: #000000">abc.ABCMeta):
    @abc.abstractmethod
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> read(self):
        </span><span style="color: #0000ff">pass</span><span style="color: #000000">
    @abc.abstractmethod
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> write(self):
        </span><span style="color: #0000ff">pass</span>
<span style="color: #008000">#</span><span style="color: #008000">父类使用了抽象类,那子类就必须继承父类的方法,而且名字也必须一样</span><span style="color: #008000">
#</span><span style="color: #008000">这样就实现了代码级别的限制</span>

<span style="color: #0000ff">class</span><span style="color: #000000"> Txt(File):
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> read(self):
        </span><span style="color: #0000ff">print</span>(<span style="color: #800000">'</span><span style="color: #800000">文本文档的读取方式</span><span style="color: #800000">'</span><span style="color: #000000">)
    </span><span style="color: #0000ff">def</span><span style="color: #000000"> write(self):
        </span><span style="color: #0000ff">print</span>(<span style="color: #800000">'</span><span style="color: #800000">文本文档的写入方式</span><span style="color: #800000">'</span>)

 

4.继承的实现原理

1)继承顺序:

python支持多继承,当一个类继承多个父类时,继承顺序是怎样的呢?这个顺序在新式类和经典类中是不一样的。

在新式类中,继承顺序是广度优先,在经典类中是深度优先,举个栗子:

图不重要,看内容
在这个图中,H是子类,H继承E,F,G,E,F,G,又分别继承B,C,D,B,C,D,同时继承A

在新式类中的顺序是:H E B F C G D A 

在经典类中的顺序是:H E B A F C G D

2)继承原理:

当我们定义一个类后,Python就会根据上面的继承规律解析出一个继承顺序的列表(MRO列表),可以通过mro()查看,但是这个方法只有在新式类中才有,经典类没有

mro

 

以上是Python物件導向程式設計(二)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn