1. 程式人生 > >第九篇:面向對象之多態與封裝

第九篇:面向對象之多態與封裝

bst 如果 正常 允許 階段 public rop 序列類型 邏輯

一 多態

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

動物有多種形態:人,狗,豬(咳咳~人也是猴子進化來的,不允許反駁技術分享圖片

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)
‘‘‘

寫到這裏,我突然想到了鴨子類型技術分享圖片

沒錯,那我就想copy一段話了

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

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

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

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

2 封裝

從封裝本身的意思去理解,封裝就好像是拿來一個麻袋,把小貓,小狗,小王八,還有李林一起裝進麻袋,然後把麻袋封上口子。照這種邏輯看,封裝=‘隱藏’,這種理解是相當片面的

一 先看如何隱藏

在python中用雙下劃線開頭的方式將屬性隱藏起來(設置成私有的)

#其實這僅僅這是一種變形操作且僅僅只在類定義階段發生變形
#類中所有雙下劃線開頭的名稱如__x都會在類定義時自動變形成:_類名__x的形式:

class A:
    __N=0 #類的數據屬性就應該是共享的,但是語法上是可以把類的數據屬性設置成私有的如__N,會變形為_A__N
    def __init__(self):
        self.__X=10 #變形為self._A__X
    def __foo(self): #變形為_A__foo
        print(from A)
    def bar(self):
        self.__foo() #只有在類內部才可以通過__foo的形式訪問到.

#A._A__N是可以訪問到的,
#這種,在外部是無法通過__x這個名字訪問到。

在繼承中,父類如果不想讓子類覆蓋自己的方法,可以將方法定義為私有

技術分享圖片
#正常情況
>>> class A:
...     def fa(self):
...         print(from A)
...     def test(self):
...         self.fa()
... 
>>> class B(A):
...     def fa(self):
...         print(from B)
... 
>>> b=B()
>>> b.test()
from B
 

#把fa定義成私有的,即__fa
>>> class A:
...     def __fa(self): #在定義時就變形為_A__fa
...         print(from A)
...     def test(self):
...         self.__fa() #只會與自己所在的類為準,即調用_A__fa
... 
>>> class B(A):
...     def __fa(self):
...         print(from B)
... 
>>> b=B()
>>> b.test()
from A
View Code

封裝其實不是單純意義的隱藏

封裝的真諦在於明確地區分內外,封裝的屬性可以直接在內部使用,而不能被外部直接使用,然而定義屬性的目的終歸是要用,外部要想用類隱藏的屬性,需要我們為其開辟接口,讓外部能夠間接地用到我們隱藏起來的屬性,那這麽做的意義何在???

1:封裝數據:將數據隱藏起來這不是目的。隱藏起來然後對外提供操作該數據的接口,然後我們可以在接口附加上對該數據操作的限制,以此完成對數據屬性操作的嚴格控制。

技術分享圖片
class Teacher:
    def __init__(self,name,age):
        # self.__name=name
        # self.__age=age
        self.set_info(name,age)

    def tell_info(self):
        print(姓名:%s,年齡:%s %(self.__name,self.__age))
    def set_info(self,name,age):
        if not isinstance(name,str):
            raise TypeError(姓名必須是字符串類型)
        if not isinstance(age,int):
            raise TypeError(年齡必須是整型)
        self.__name=name
        self.__age=age


t=Teacher(egon,18)
t.tell_info()

t.set_info(egon,19)
t.tell_info()
:(

2:封裝方法:目的是隔離復雜度

封裝方法舉例:

1. 你的身體沒有一處不體現著封裝的概念:你的身體把膀胱尿道等等這些尿的功能隱藏了起來,然後為你提供一個尿的接口就可以了(接口就是你的。。。,),你總不能把膀胱掛在身體外面,上廁所的時候就跟別人炫耀:hi,man,你瞅我的膀胱,看看我是怎麽尿的。

2. 電視機本身是一個黑盒子,隱藏了所有細節,但是一定會對外提供了一堆按鈕,這些按鈕也正是接口的概念,所以說,封裝並不是單純意義的隱藏!!!

3. 快門就是傻瓜相機為傻瓜們提供的方法,該方法將內部復雜的照相功能都隱藏起來了

提示:在編程語言裏,對外提供的接口(接口可理解為了一個入口),可以是函數,稱為接口函數,這與接口的概念還不一樣,接口代表一組接口函數的集合體

   

四 特性(property)

什麽是特性property

property是一種特殊的屬性,訪問它時會執行一段功能(函數)然後返回值

例一:BMI指數(bmi是計算而來的,但很明顯它聽起來像是一個屬性而非方法,如果我們將其做成一個屬性,更便於理解)

成人的BMI數值: 過輕:低於18.5 正常:18.5-23.9 過重:24-27 肥胖:28-32 非常肥胖, 高於32   體質指數(BMI)=體重(kg)÷身高^2(m)   EX:70kg÷(1.75×1.75)=22.86 技術分享圖片
class People:
    def __init__(self,name,weight,height):
        self.name=name
        self.weight=weight
        self.height=height
    @property
    def bmi(self):
        return self.weight / (self.height**2)

p1=People(egon,75,1.85)
print(p1.bmi)
沒錯就是這樣

為什麽要用property

將一個類的函數定義成特性以後,對象再去使用的時候obj.name,根本無法察覺自己的name是執行了一個函數然後計算出來的,這種特性的使用方式遵循了統一訪問的原則

除此之外,看下

ps:面向對象的封裝有三種方式:
【public】
這種其實就是不封裝,是對外公開的
【protected】
這種封裝方式對外不公開,但對朋友(friend)或者子類(形象的說法是“兒子”,但我不知道為什麽大家 不說“女兒”,就像“parent”本來是“父母”的意思,但中文都是叫“父類”)公開
【private】
這種封裝對誰都不公開

第九篇:面向對象之多態與封裝