python基礎(25):面向對象三大特性二(多態、封裝)

来源:https://www.cnblogs.com/liuhui0308/archive/2019/11/13/11853872.html
-Advertisement-
Play Games

1. 多態 1.1 什麼是多態 多態指的是一類事物有多種形態。 動物有多種形態:人,狗,豬。 import abc class Animal(metaclass=abc.ABCMeta): #同一類事物:動物 @abc.abstractmethod def talk(self): pass clas ...


1. 多態

1.1 什麼是多態

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

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

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

1.2 多態性

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

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

在面向對象方法中一般是這樣表述多態性:
向不同的對象發送同一條消息(!!!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()

2. 封裝

2.1 什麼叫封裝

隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。

好處:

1. 將變化隔離; 

2. 便於使用;

3. 提高復用性; 

4. 提高安全性。

封裝原則:

1. 將不需要對外提供的內容都隱藏起來;

2. 把屬性都隱藏,提供公共方法對其訪問。

2.2 私有變數和私有方法

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

2.2.1 私有變數

#其實這僅僅這是一種變形操作
#類中所有雙下劃線開頭的名稱如__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是可以訪問到的,即這種操作並不是嚴格意義上的限制外部訪問,僅僅只是一種語法意義上的變形

這種自動變形的特點:

1.類中定義的__x只能在內部使用,如self.__x,引用的就是變形的結果。

2.這種變形其實正是針對外部的變形,在外部是無法通過__x這個名字訪問到的。

3.在子類定義的__x不會覆蓋在父類定義的__x,因為子類中變形成了:_子類名__x,而父類中變形成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是無法覆蓋的。

這種變形需要註意的問題是:

1.這種機制也並沒有真正意義上限制我們從外部直接訪問屬性,知道了類名和屬性名就可以拼出名字:_類名__屬性,然後就可以訪問了,如a._A__N

2.變形的過程只在類的內部生效,在定義後的賦值操作,不會變形

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

2.2.2 私有方法

#正常情況
>>> 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

2.3 封裝與擴展性

封裝在於明確區分內外,使得類實現者可以修改封裝內的東西而不影響外部調用者的代碼;而外部使用用者只知道一個介面(函數),只要介面(函數)名、參數不變,使用者的代碼永遠無需改變。這就提供一個良好的合作基礎——或者說,只要介面這個基礎約定不變,則代碼改變不足為慮。

#類的設計者
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #對外提供的介面,隱藏了內部的實現細節,此時我們想求的是面積
        return self.__width * self.__length

#使用者
>>> r1=Room('卧室','egon',20,20,20)
>>> r1.tell_area() #使用者調用介面tell_area

#類的設計者,輕鬆的擴展了功能,而類的使用者完全不需要改變自己的代碼
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #對外提供的介面,隱藏內部實現,此時我們想求的是體積,內部邏輯變了,只需求修該下列一行就可以很簡答的實現,而且外部調用感知不到,仍然使用該方法,但是功能已經變了
        return self.__width * self.__length * self.__high

#對於仍然在使用tell_area介面的人來說,根本無需改動自己的代碼,就可以用上新功能
>>> r1.tell_area()

2.4 property屬性

什麼是特性property?

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

除此之外,看下:

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

python並沒有在語法上把它們三個內建到自己的class機制中,在C++里一般會將所有的所有的數據都設置為私有的,然後提供set和get方法(介面)去設置和獲取,在python中通過property方法可以實現。

class Foo:
    def __init__(self,val):
        self.__NAME=val #將所有的數據屬性都隱藏起來

    @property
    def name(self):
        return self.__NAME #obj.name訪問的是self.__NAME(這也是真實值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在設定值之前進行類型檢查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通過類型檢查後,將值value存放到真實的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('egon')
print(f.name)
# f.name=10 #拋出異常'TypeError: 10 must be str'
del f.name #拋出異常'TypeError: Can not delete'

一個靜態屬性property本質就是實現了get,set,delete三種方法。

class Foo:
    @property
    def AAA(self):
        print('get的時候運行我啊')

    @AAA.setter
    def AAA(self,value):
        print('set的時候運行我啊')

    @AAA.deleter
    def AAA(self):
        print('delete的時候運行我啊')

#只有在屬性AAA定義property後才能定義AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
class Foo:
    def get_AAA(self):
        print('get的時候運行我啊')

    def set_AAA(self,value):
        print('set的時候運行我啊')

    def delete_AAA(self):
        print('delete的時候運行我啊')
    AAA=property(get_AAA,set_AAA,delete_AAA) #內置property三個參數與get,set,delete一一對應

f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA

怎麼用?

class Goods:

    def __init__(self):
        # 原價
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    @property
    def price(self):
        # 實際價格 = 原價 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deleter
    def price(self):
        del self.original_price

obj = Goods()
obj.price         # 獲取商品價格
obj.price = 200   # 修改商品原價
print(obj.price)
del obj.price     # 刪除商品原價

2.5 classmethod

class Classmethod_Demo():
    role = 'dog'

    @classmethod
    def func(cls):
        print(cls.role)

Classmethod_Demo.func()

2.6 staticmethod

class Staticmethod_Demo():
    role = 'dog'

    @staticmethod
    def func():
        print("當普通方法用")

Staticmethod_Demo.func()

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 你好,我是彤哥,本篇是netty系列的第二篇。 簡介 本文將介紹linux中的五種IO模型,同時也會介紹阻塞/非阻塞與同步/非同步的區別。 何為IO模型 對於一次IO操作,數據會先拷貝到內核空間中,然後再從內核空間拷貝到用戶空間中,所以一次read操作,會經歷兩個階段: (1) 等待數據準備 (2) ...
  • 1.打開PyCharm,選擇File--Settings 2.依次選擇Editor Code Style-- File and Code Templates Python Script 3..添加頭部內容 可以根據需要添加相應的信息 #!/usr/bin/python3 可用的預定義文件模板變數為: ...
  • 場景 豬肉價格網站: http://zhujia.zhuwang.cc/ 註: 博客: https://blog.csdn.net/badao_liumang_qizhi 關註公眾號 霸道的程式猿 獲取編程相關電子書、教程推送與免費下載。 實現 使用谷歌瀏覽器打開F12,刷新下當前網頁,找到Netw ...
  • 資料庫,一個我們常常提到的名詞,但是你有沒有想過,它到底是什麼意思呢,而我們常說的 MySQL、Oracle 等又到底指什麼呢? 資料庫 資料庫(DataBase),簡稱 DB,是資料庫是存儲數據的集合,你可以把它理解為多個數據表。資料庫是“按照數據結構來組織、存儲和管理數據的倉庫”,是一個長期存儲 ...
  • 之前一直使用的是MySQL5.7,但由於MySQL增加了一些新特性,所以選擇了更新。 下載MySQL 進入MySQL官網下載地址,選擇Windows (x86, 64 bit), ZIP Archive。 下載地址: 可不用登錄,直接跳過。下載過程也許有丟丟慢,耐心等待下。 下載完成後,直接解壓到自 ...
  • 首先要先把環境變數配置好,配置好環境變數打開go文件的時候,會自動提示需要安裝的擴展在/root/.profile和/home/當前用戶/.profile都加上 export GOPATH=/var/www/html/go-project/libexport GOROOT=/usr/local/go ...
  • 本文收錄在Python從入門到精通系列文章系列 在分享本章節的內容之前,先來研究一道數學題,請說出下麵的方程有多少組正整數解。 事實上,上面的問題等同於將8個蘋果分成四組每組至少一個蘋果有多少種方案。想到這一點問題的答案就呼之欲出了。 可以用Python的程式來計算出這個值,代碼如下所示。 """ ...
  • class Solution: """ @param A: an integer array @return: nothing """ def sortIntegers(self, A): new_list = list(A) list_len = len(new_list) for i in ra... ...
一周排行
    -Advertisement-
    Play Games
  • 前言 插件化的需求主要源於對軟體架構靈活性的追求,特別是在開發大型、複雜或需要不斷更新的軟體系統時,插件化可以提高軟體系統的可擴展性、可定製性、隔離性、安全性、可維護性、模塊化、易於升級和更新以及支持第三方開發等方面的能力,從而滿足不斷變化的業務需求和技術挑戰。 一、插件化探索 在WPF中我們想要開 ...
  • 歡迎ReaLTaiizor是一個用戶友好的、以設計為中心的.NET WinForms項目控制項庫,包含廣泛的組件。您可以使用不同的主題選項對項目進行個性化設置,並自定義用戶控制項,以使您的應用程式更加專業。 項目地址:https://github.com/Taiizor/ReaLTaiizor 步驟1: ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • Channel 是乾什麼的 The System.Threading.Channels namespace provides a set of synchronization data structures for passing data between producers and consume ...
  • efcore如何優雅的實現按年分庫按月分表 介紹 本文ShardinfCore版本 本期主角: ShardingCore 一款ef-core下高性能、輕量級針對分表分庫讀寫分離的解決方案,具有零依賴、零學習成本、零業務代碼入侵適配 距離上次發文.net相關的已經有很久了,期間一直在從事java相關的 ...
  • 前言 Spacesniffer 是一個免費的文件掃描工具,通過使用樹狀圖可視化佈局,可以立即瞭解大文件夾的位置,幫助用戶處理找到這些文件夾 當前系統C盤空間 清理後系統C盤空間 下載 Spacesniffer 下載地址:https://spacesniffer.en.softonic.com/dow ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • 一、ReZero簡介 ReZero是一款.NET中間件 : 全網唯一開源界面操作就能生成API , 可以集成到任何.NET6+ API項目,無破壞性,也可讓非.NET用戶使用exe文件 免費開源:MIT最寬鬆協議 , 一直從事開源事業十年,一直堅持開源 1.1 純ReZero開發 適合.Net Co ...
  • 一:背景 1. 講故事 停了一個月沒有更新文章了,主要是忙於寫 C#內功修煉系列的PPT,現在基本上接近尾聲,可以回頭繼續更新這段時間分析dump的一些事故報告,有朋友微信上找到我,說他們的系統出現了大量的http超時,程式不響應處理了,讓我幫忙看下怎麼回事,dump也抓到了。 二:WinDbg分析 ...
  • 開始做項目管理了(本人3年java,來到這邊之後真沒想到...),天天開會溝通整理需求,他們講話的時候忙裡偷閑整理一下常用的方法,其實語言還是有共通性的,基本上看到方法名就大概能猜出來用法。出去打水的時候看到外面太陽好好,真想在外面坐著曬太陽,回來的時候好兄弟三年前送給我的鍵盤D鍵不靈了,在打"等待 ...