類三大特性(繼承 多態 封裝)


繼承

  1 先說下什么是經典類 什么事是新式類

     Python 2 當中類分為新式類和經典類 Python 3中全部叫新式類  python 2中如果有繼承父類是object 就是新式類,繼承其他類不算,但是如果繼承其他類,其他類有其他了object 那就是新式類

    經典類:

    class 類名:
      pass

 

    新式類:
    class 類名(object):
      pass

 

  2 Python 2 繼承,如果類是經典類,繼承方式如下圖

  

 

  3 Python 3 繼承因為python 3 都是新式類 如果python 2是新式類也是這樣的繼承

   

class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): # def test(self):
    # print('from F')
    pass f1=F() f1.test() print(F.__mro__) #只有新式才有這個屬性可以查看線性列表,經典類沒有這個屬性

#新式類繼承順序:F->D->B->E->C->A #經典類繼承順序:F->D->B->A->E->C #python3中統一都是新式類 #pyhon2中才分新式類與經典類

 

4  繼承原理(python如何實現的繼承)python 2中沒有__mro__

python到底是如何實現繼承的,對於你定義的每一個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表,例如

>>> F.mro() #等同於F.__mro__
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

 

為了實現繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。
而這個MRO列表的構造是通過一個C3線性化算法來實現的。我們不去深究這個算法的數學原理,它實際上就是合並所有父類的MRO列表並遵循如下三條准則:
1.子類會先於父類被檢查
2.多個父類會根據它們在列表中的順序被檢查
3.如果對下一個類存在兩個合法的選擇,選擇第一個父類

 

5 super()子類中調用父類的方法

class A(object): def __init__(self,name): self.name = name print(self.name) def run(self): print('測試測試測試') print(self.name) class B(A): def __init__(self,age): self.age = age super().__init__('王Sir')  #調用父類中的__init__方法
        #super(B,self).__init__('王Sir') #還有另外一種調用方法,跟上面一樣

    def test(self): super().run() #調用父類中的run方法 self都不用寫了
        print('test') ret = B('22') ret.run() # 結果為: # 王Sir # 測試測試測試 # 王Sir

 

一 多態

多態指的是一類事物有多種形態

動物有多種形態:人,狗,豬

復制代碼
import abc
class Animal(metaclass=abc.ABCMeta): #同一類事物:動物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #動物的形態之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #動物的形態之二:狗
    def talk(self):
        print('say wangwang')

class Pig(Animal): #動物的形態之三:豬
    def talk(self):
        print('say aoao')
復制代碼

文件有多種形態:文本文件,可執行文件

復制代碼
import abc
class File(metaclass=abc.ABCMeta): #同一類事物:文件
    @abc.abstractmethod
    def click(self):
        pass

class Text(File): #文件的形態之一:文本文件
    def click(self):
        print('open file')

class ExeFile(File): #文件的形態之二:可執行文件
    def click(self):
        print('execute file')
復制代碼

 

二 多態性

一 什么是多態動態綁定(在繼承的背景下使用時,有時也稱為多態性)

多態性是指在不考慮實例類型的情況下使用實例

 在面向對象方法中一般是這樣表述多態性:向不同的對象發送同一條消息(!!!obj.func():是調用了obj的方法func,又稱為向obj發送了一條消息func),不同的對象在接收時會產生不同的行為(即方法)。也就是說,每個對象可以用自己的方式去響應共同的消息。所謂消息,就是調用函數,不同的行為就是指不同的實現,即執行不同的函數。比如:老師.下課鈴響了(),學生.下課鈴響了(),老師執行的是下班操作,學生執行的是放學操作,雖然二者消息一樣,但是執行的效果不同

 

多態性分為靜態多態性和動態多態性

  靜態多態性:如任何類型都可以用運算符+進行運算

  動態多態性:如下

復制代碼
peo=People()
dog=Dog()
pig=Pig()

#peo、dog、pig都是動物,只要是動物肯定有talk方法
#於是我們可以不用考慮它們三者的具體是什么類型,而直接使用
peo.talk()
dog.talk()
pig.talk()

#更進一步,我們可以定義一個統一的接口來使用
def func(obj):
    obj.talk()
復制代碼

二 為什么要用多態性(多態性的好處)

其實大家從上面多態性的例子可以看出,我們並沒有增加什么新的知識,也就是說python本身就是支持多態性的,這么做的好處是什么呢?

1.增加了程序的靈活性

  以不變應萬變,不論對象千變萬化,使用者都是同一種形式去調用,如func(animal)

2.增加了程序額可擴展性

  通過繼承animal類創建了一個新的類,使用者無需更改自己的代碼,還是用func(animal)去調用     

復制代碼
>>> class Cat(Animal): #屬於動物的另外一種形態:貓
...     def talk(self):
...         print('say miao')
... 
>>> def func(animal): #對於使用者來說,自己的代碼根本無需改動
...     animal.talk()
... 
>>> cat1=Cat() #實例出一只貓
>>> func(cat1) #甚至連調用方式也無需改變,就能調用貓的talk功能
say miao

'''
這樣我們新增了一個形態Cat,由Cat類產生的實例cat1,使用者可以在完全不需要修改自己代碼的情況下。使用和人、狗、豬一樣的方式調用cat1的talk方法,即func(cat1)
'''
復制代碼

 

 

三  鴨子類型

逗比時刻:

  Python崇尚鴨子類型,即‘如果看起來像、叫聲像而且走起路來像鴨子,那么它就是鴨子’

python程序員通常根據這種行為來編寫程序。例如,如果想編寫現有對象的自定義版本,可以繼承該對象

也可以創建一個外觀和行為像,但與它無任何關系的全新對象,后者通常用於保存程序組件的松耦合度。

例1:利用標准庫中定義的各種‘與文件類似’的對象,盡管這些對象的工作方式像文件,但他們沒有繼承內置文件對象的方法

 

#二者都像鴨子,二者看起來都像文件,因而就可以當文件一樣去用
class TxtFile:
    def read(self):
        pass

    def write(self):
        pass

class DiskFile:
    def read(self):
        pass
    def write(self):
        pass

例2:其實大家一直在享受着多態性帶來的好處,比如Python的序列類型有多種形態:字符串,列表,元組,多態性體現如下

#str,list,tuple都是序列類型
s=str('hello')
l=list([1,2,3])
t=tuple((4,5,6))

#我們可以在不考慮三者類型的前提下使用s,l,t
s.__len__()
l.__len__()
t.__len__()

len(s)
len(l)
len(t)

封裝(實際封裝python中的封裝只是一個約定)
第一個層面的封裝:類就是一個袋子,這就是一種封裝
第二個層面的封裝:類中定義私有的,只有類內部使用,外部無法訪問(比如_(杠) __(杠杠) )
class hj:
_arg = 'world' #封裝
__kws = 'kws' #封裝
def __init__(self):
print(self._arg) #內部調用一個下划線的封裝
print(self.__kws) #內部調用兩個下划線的封裝

#提供封裝訪問函數讓外部可以使用
def get(self):
print(self.__kws)

h = hj()
print(h._arg) #一個下划線的封裝 外部是可以調用的
#print(h.__kws) #兩個下划線的封裝 外部是無法調用的(其實是可以調用的,只不過python給你做個一個重名的操作(_hj__kws))
h.get()
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM