python:面向?qū)ο?/h2>

自己以前整理的筆記,不太完整,后續(xù)會(huì)不斷更新。。。。


  • [ ] __new__方法擴(kuò)展
  • [ ] 魔法方法
  • [ ] 什么情況下使用self,什么情況不用?

面向過(guò)程和面向?qū)ο笫莾煞N不同的編程方式

一、面向過(guò)程

過(guò)程:是早期的一種編程概念,類似于函數(shù),但只有執(zhí)行,沒有返回值

面向過(guò)程:把能實(shí)現(xiàn)某些獨(dú)立功能的代碼封裝成一個(gè)個(gè)函數(shù),然后順序調(diào)用不同的函數(shù)

特點(diǎn)

  • 過(guò)程與步驟---怎么做?
  • 若需求復(fù)雜,代碼也會(huì)變復(fù)雜

二、面向?qū)ο螅∣bject Oriented Programming)

具體的事物抽象化,抽象的事物具象化---前者針對(duì)實(shí)際存在的事物,后者針對(duì)抽象的事物

特點(diǎn)

  • 相比于函數(shù),面向?qū)ο笫歉蟮姆庋b,一個(gè)對(duì)象可根據(jù)職責(zé)封裝多個(gè)方法
  • 注重對(duì)象和職責(zé)---誰(shuí)來(lái)做?
  • 適合復(fù)雜項(xiàng)目開發(fā),提供固定的套路

對(duì)象的三大特性

  • 封裝:封裝屬性和方法
  • 繼承:實(shí)現(xiàn)代碼的重用
  • 多態(tài):對(duì)封裝和繼承的功能擴(kuò)展:對(duì)象調(diào)用的方法,在子類和父類中都可以有,父類中有,子類可重寫,由此不同的子類可實(shí)現(xiàn)不同的功能

三、類

  • 抽象
  • 屬性
  • 方法

類用來(lái)創(chuàng)建對(duì)象

對(duì)象是類的具象、實(shí)例化

類只有一個(gè),對(duì)應(yīng)的對(duì)象有多個(gè):不同對(duì)象之間的屬性可能不同

三要素

  1. 類名:大駝峰命名
  2. 屬性:特征
  3. 方法:行為

01.對(duì)象

  1. 每一次實(shí)例化的對(duì)象所保存的地址都不同
  2. 臨時(shí)為對(duì)象添加屬性的方法:直接給對(duì)象賦值 -----不推薦,未修改類

dir()內(nèi)建函數(shù)

使用dir()可傳入任意對(duì)象,查看對(duì)象的所有屬性及方法

顯示出的__方法名__格式的方法是python提供的內(nèi)置屬性/方法

對(duì)象初始化-引用

  • 創(chuàng)建對(duì)象后,變量保存的是對(duì)象在內(nèi)存中的地址
  • 變量引用(指向)了新建的對(duì)象
  • print打印變量,顯示該變量引用的對(duì)象是由哪一個(gè)類創(chuàng)建的對(duì)象,及內(nèi)存中的地址

對(duì)象創(chuàng)建過(guò)程-原理

  • 當(dāng)使用 類名( ) 創(chuàng)建對(duì)象時(shí),會(huì)自動(dòng)執(zhí)行以下操作:
    1. 為對(duì)象在內(nèi)存中 分配空間 —— 創(chuàng)建對(duì)象
    2. 為對(duì)象的屬性 設(shè)置初始值 —— 初始化方法 _init_()
  • 這個(gè) 初始化方法 就是 __init__ 方法,__init__ 是對(duì)象的內(nèi)置方法,創(chuàng)建對(duì)象時(shí)自動(dòng)調(diào)用該方法

__init__ 方法是 專門 用來(lái)定義一個(gè)類 具有哪些屬性的方法!

self

  • 哪一個(gè)對(duì)象 調(diào)用的方法,方法內(nèi)的self就是 哪一個(gè)對(duì)象的引用
  • 對(duì)象調(diào)用方法時(shí),不需要傳遞self參數(shù)
  • 類中定義方法時(shí)可通過(guò)self.的方式訪問屬性及調(diào)用其他方法

02.內(nèi)置方法

_init_()

當(dāng)使用 類名( ) 創(chuàng)建對(duì)象時(shí),分配完內(nèi)存空間后,自動(dòng)調(diào)用該方法

  • 創(chuàng)建對(duì)象時(shí)類名( )中的實(shí)參傳入到__init__( )中除self之外的其他形參中
  • 若屬性有初始值則不適合作為形參在對(duì)象初始化的時(shí)候傳入,可在該方法內(nèi)直接賦值
  • 若某屬性的初始值不確定,可在該方法內(nèi)賦值為None

_del_()與del

當(dāng)一個(gè)對(duì)象被從內(nèi)存銷毀前,會(huì)自動(dòng)調(diào)用該方法

class Cat:
    def __init__(self, new_name):

        self.name = new_name
        print('初始化調(diào)用')

    def __del__(self):

        print('銷毀前調(diào)用')


# 整個(gè)程序結(jié)束后對(duì)象才會(huì)被銷毀
tom = Cat('Tom')
print(tom.name)

# del tom   # 使用del,提前調(diào)用__del()銷毀對(duì)象

print('_'*50)

_str_()

定制化print出的內(nèi)容

  • 必須要return 一個(gè)字符串
  • 用于print()對(duì)象時(shí)的顯示結(jié)果
  • 如果不定義該方法,打印對(duì)象時(shí)返回結(jié)果為十六進(jìn)制內(nèi)存地址

__class__屬性

每一個(gè)實(shí)例對(duì)象中都存在一個(gè)__class__屬性,指向創(chuàng)建該對(duì)象的類對(duì)象

03.私有屬性和私有方法

定義

私有屬性/私有方法:在屬性名稱/方法名稱前加__(兩個(gè)下劃線)

特點(diǎn)

私有屬性和方法無(wú)法在類外訪問,只能在類中訪問

偽私有:python中不存在真正意義上的私有,私有屬性和方法可以通過(guò)以下格式訪問

對(duì)象._類名.__屬性/方法

實(shí)際上是python對(duì)私有屬性和方法改名了

class Women:

    def __init__(self, name):

        self.name = name
        # 不要問女生的年齡
        self.__age = 18

    def __secret(self):
        print("我的年齡是 %d" % self.__age)

xiaofang = Women('小芳')
print(xiaofang._Women.__age)
xiaofang._Women.__secret()

注意:

# *-* coding:utf-8 *-*
# 私有屬性只能在類中定義


class Test(object):
    def __init__(self, name):
        self.__name = name


a = Test('老王')
print(a._Test__name)  # 可訪問

print(a.__dict__)  # 查看a對(duì)象的所有屬性
# 實(shí)際上是__name被解釋器名字重整為_Test__name

a.__name='老李'  # 添加一個(gè)屬性,屬性名為__name
print(a.__name)
print(a.__dict__)


# 結(jié)果
老王
{'_Test__name': '老王'}
老李
{'_Test__name': '老王', '__name': '老李'}

四、繼承

概念:子類擁有父類的所有屬性和方法

子類在自己方法內(nèi)不能直接訪問父類的私有屬性和私有方法,但可以通過(guò)父類的公有方法間接訪問私有屬性和方法

屬性

  • 繼承的傳遞性:‘孫類’不僅繼承父類的屬性和方法,還會(huì)繼承‘爺類’的屬性和方法

01. 多重繼承

子類方法的重寫:

父類的方法實(shí)現(xiàn)無(wú)法滿足子類的需求

  1. 覆蓋父類方法
  2. 對(duì)父類方法進(jìn)行擴(kuò)展:
  • super( ).方法( ): super( )的主要作用是擴(kuò)展父類中已有方法的功能

若父類中都存在某方法,則一直向上找,直到找到為止

也就是說(shuō)向上只能找到第一個(gè)某方法

  • super(class1,self).方法1():繼承class1父類的方法1
  • 父類名.方法(self): 調(diào)用父類中的方法,若父類中沒有該方法則去父類的父類中查找

若所有父類中都存在同一名稱的方法,那么可以用這種方法調(diào)用特定類中的方法

super().__init__相對(duì)于 類名.__init__,在單繼承上用法基本無(wú)差,但在多繼承上有區(qū)別,super方法能保證每個(gè)父類的方法只會(huì)執(zhí)行一次,而使用類名的方法會(huì)導(dǎo)致方法被執(zhí)行多次,如下的案例:

http://www.cnblogs.com/dkblog/archive/2011/02/24/1980654.html

02. 多繼承

class B:
    pass
class C:
    pass

class A(B, C):
    pass

開發(fā)時(shí)若多個(gè)父類中的屬性或方法名稱相同時(shí),應(yīng)盡量避免使用多繼承,否則容易混淆

python中針對(duì)提供了內(nèi)置屬性__mro__可以查看子類對(duì)多繼承的父類的搜索順序

print(A.__mro__)
# 結(jié)果
# (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
  • 在搜索方法時(shí),是按照 __mro__ 的輸出結(jié)果 從左至右 的順序查找的
  • 如果在當(dāng)前類中 找到方法,就直接執(zhí)行,不再搜索
  • 如果 沒有找到,就查找下一個(gè)類 中是否有對(duì)應(yīng)的方法,如果找到,就直接執(zhí)行,不再搜索
  • 如果找到最后一個(gè)類,還沒有找到方法,程序報(bào)錯(cuò)

object類是python中所有類的基類,提供一些內(nèi)置的屬性和方法

新式類與舊式(經(jīng)典)類

  • 新式類:

默認(rèn)以object類為基類

多繼承時(shí),搜索父類時(shí)采用廣度優(yōu)先原則

python3.x中都是新式類

  • 經(jīng)典類:

不默認(rèn)以object類為基類

多繼承時(shí),搜索父類時(shí)采用深度優(yōu)先原則

python2.x中,若不指定父類,不會(huì)以object類作為基類

建議:為保證代碼在2.x和3.x中均能運(yùn)行,只要沒有父類,都寫上object作為父類

當(dāng)所有父類都有共同的父類時(shí),在到達(dá)共有父類之前先按深度優(yōu)先原則,再按廣度優(yōu)先原則進(jìn)行繼承

幾種多繼承方式:

1534734241591.png
1534735028431.png
1534735159033.png

一個(gè)坑

# 新式類繼承順序,廣度優(yōu)先原則
class A:
    pass
class B(A):
    pass
# 報(bào)錯(cuò):繼承順序回頭,C--->A--->B--->A
class C(A,B):
    pass
print(C.__mro__)

# 正常:繼承順序,C--->B--->A--->?
class C(B,A):
    pass
print(C.__mro__)

五、多態(tài)

不同的子類對(duì)象調(diào)用相同的父類方法,產(chǎn)生不同的執(zhí)行結(jié)果

特點(diǎn):

  • 多態(tài)可增加代碼的靈活度
  • 繼承重寫父類方法為前提
  • 不影響父類的內(nèi)部

多態(tài)的好處就是,當(dāng)我們需要傳入Dog、Cat、Tortoise……時(shí),我們只需要接收Animal類型就可以了,因?yàn)镈og、Cat、Tortoise……都是Animal類型,然后,按照Animal類型進(jìn)行操作即可。由于Animal類型有run()方法,因此,傳入的任意類型,只要是Animal類或者子類,就會(huì)自動(dòng)調(diào)用實(shí)際類型的run()方法,這就是多態(tài)的意思:

對(duì)于一個(gè)變量,我們只需要知道它是Animal類型,無(wú)需確切地知道它的子類型,就可以放心地調(diào)用run()方法 ,而具體調(diào)用的run()方法是作用在Animal、Dog、Cat還是Tortoise對(duì)象上,由運(yùn)行時(shí)該對(duì)象的確切類型決定,這就是多態(tài)真正的威力:調(diào)用方只管調(diào)用,不管細(xì)節(jié),而當(dāng)我們新增一種Animal的子類時(shí),只要確保run()方法編寫正確,不用管原來(lái)的代碼是如何調(diào)用的。這就是著名的“開閉”原則:

**對(duì)擴(kuò)展開放:允許子類重寫父類方法函數(shù) **

**對(duì)修改封閉:不重寫,直接繼承父類方法函數(shù) **

六、類屬性和類方法

從類的實(shí)例化講起:

每次通過(guò) 類名( ) 創(chuàng)建對(duì)象的動(dòng)作有兩步:

  1. 在內(nèi)存中為對(duì)象 分配空間

  2. 調(diào)用初始化方法 __init__對(duì)象初始化

對(duì)象創(chuàng)建后,內(nèi)存 中就有了一個(gè)對(duì)象的 實(shí)實(shí)在在 的存在 —— 實(shí)例

對(duì)象的屬性叫實(shí)例屬性,對(duì)象調(diào)用的方法叫實(shí)例方法

01 內(nèi)存空間分配

如圖,一個(gè)類可實(shí)例化為多個(gè)對(duì)象,但

  • 每一個(gè)對(duì)象 都有自己 獨(dú)立的內(nèi)存空間,保存各自不同的屬性
  • 多個(gè)對(duì)象的方法,在內(nèi)存中只有一份,保存在類所在的內(nèi)存空間,在調(diào)用方法時(shí),需要把對(duì)象的引用 傳遞到方法內(nèi)部即可
  • 在程序運(yùn)行時(shí),會(huì)被加載到內(nèi)存
  • 每個(gè)實(shí)例對(duì)象內(nèi)都存在一個(gè)內(nèi)置屬性__class__,保存著該屬性是由哪個(gè)類創(chuàng)建的
1550899375695.png
QQ20171025-204706@2x.png

02 類是一個(gè)特殊的對(duì)象

class A: 定義的類屬于類對(duì)象

obj=A( ): 定義的對(duì)象屬于實(shí)例對(duì)象

  • 類對(duì)象在內(nèi)存中只有一份
  • 類對(duì)象也有自己的屬性和方法,分別叫類屬性類方法
  • 通過(guò) 類名. 的方式可訪問類屬性和類方法

類對(duì)象與實(shí)例對(duì)象互相訪問權(quán)限

  1. 類對(duì)象-->實(shí)例對(duì)象

類對(duì)象不可以訪問實(shí)例對(duì)象的屬性和方法

  1. 實(shí)例對(duì)象-->類對(duì)象

實(shí)例對(duì)象可以訪問類屬性(前提:實(shí)例對(duì)象中無(wú)同名屬性)和類方法(且實(shí)例方法不能與類方法重名,否則無(wú)效,只調(diào)用類方法)

實(shí)例對(duì)象也可訪問靜態(tài)方法

03 類屬性

在類對(duì)象中定義的屬性,通常會(huì)用來(lái)記錄與該類有關(guān)的特征,而不會(huì)用于記錄具體對(duì)象的特征

應(yīng)用場(chǎng)景:通過(guò)類創(chuàng)建實(shí)例對(duì)象時(shí),如果每個(gè)對(duì)象需要具有相同名字的屬性,那么就使用類屬性,用一份既可

python中實(shí)例對(duì)象屬性的獲取存在一個(gè)向上查找的機(jī)制

  1. 通過(guò)對(duì)象名.屬性名方式調(diào)用屬性時(shí),首先在實(shí)例對(duì)象內(nèi)部查找
  2. 沒找到就會(huì)向上尋找同名的類屬性

所以,實(shí)例對(duì)象也可以通過(guò)對(duì)象名.類屬性的方式訪問類屬性(但不推薦)

注意:

如果給對(duì)象以對(duì)象名.類屬性=值的方式添加屬性,不會(huì)影響類屬性的值,只會(huì)給對(duì)象新建一個(gè)與類屬性同名的實(shí)例屬性

實(shí)例對(duì)象也可以通過(guò)self.__class__.類屬性給類屬性重新賦值

04 類方法

類方法 就是針對(duì) 類對(duì)象 定義的方法

類方法內(nèi)部可以直接訪問類屬性或者調(diào)用其他的類方法

# 定義類方法

@classmethod
def 類方法名(cls, var1, var2):
    pass

類方法形參第一個(gè)參數(shù)應(yīng)該是cls,其效果類似于實(shí)例方法的第一個(gè)形參self,哪一個(gè)類調(diào)用該方法,方法的cls就是那個(gè)類的引用

05 靜態(tài)方法

在類中既不需要訪問實(shí)例屬性和方法,也不需要訪問類屬性和方法的方法叫靜態(tài)方法

# 定義靜態(tài)方法
@staticmethod
def 靜態(tài)方法名():
    pass

通過(guò)類名.調(diào)用靜態(tài)方法,實(shí)例對(duì)象也可以調(diào)用靜態(tài)方法

七、單例

單例設(shè)計(jì)模式

設(shè)計(jì)模式

  • 前人工作的總結(jié)和提煉,通常,被人們廣泛流傳的設(shè)計(jì)模式都是針對(duì) 某一特定問題 的成熟的解決方案
  • 使用 設(shè)計(jì)模式 是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性

單例設(shè)計(jì)模式

讓類創(chuàng)建的對(duì)象,在系統(tǒng)內(nèi)存中只有唯一的一個(gè)實(shí)例

即:每次執(zhí)行新建對(duì)象操作所返回對(duì)象的內(nèi)存地址是相同的

應(yīng)用:音樂播放器、打印機(jī).....

01.__new__(cls)

使用類創(chuàng)建對(duì)象時(shí),python解釋器先調(diào)用__new__( )給對(duì)象分配內(nèi)存空間,然后再調(diào)用__init__( )初始化

__new__( )是object基類提供的內(nèi)置靜態(tài)方法,其功能:

  • 在內(nèi)存中為對(duì)象分配空間
  • 返回對(duì)象的引用

python解釋器獲得其返回的對(duì)象引用后,將其作為參數(shù)傳遞給__init__( )方法的第一個(gè)參數(shù)self

由以上可見:

  1. 要實(shí)現(xiàn)單例設(shè)計(jì)模式,可通過(guò)重寫__new__( )方法來(lái)控制創(chuàng)建對(duì)象時(shí)內(nèi)存空間的分配
  2. 基類objectsuper().__new__(cls)可以幫助實(shí)現(xiàn)對(duì)象內(nèi)存的分配,并返回對(duì)象的引用,也就是說(shuō),此時(shí)super().__new__(cls)是一個(gè)對(duì)象的引用
  3. 重寫 __new__ 方法 一定要 return super().__new__(cls),因?yàn)樗梢詭椭鷮?shí)現(xiàn)內(nèi)存空間分配的功能
  4. 調(diào)用時(shí)需要主動(dòng)傳遞cls參數(shù),傳遞的是類對(duì)象
  5. 由于要識(shí)別對(duì)象是否是初次調(diào)用,所以需要有一個(gè)類屬性來(lái)記錄實(shí)例對(duì)象的實(shí)例化次數(shù)
class MusicPlayer:
    count = None
    
    def __init__(self):
        print('初始化播放器對(duì)象')

    def __new__(cls):
        if MusicPlayer.count is None:
            MusicPlayer.count = super().__new__(cls)       # 基類object中的__new__方法完成了內(nèi)存的分配并返回了對(duì)象的引用
            
        print(MusicPlayer.count)
        return MusicPlayer.count                       # 要返回對(duì)象的引用


player1 = MusicPlayer()
player2 = MusicPlayer()

print(player1)
print(player2)

02.__new__方法擴(kuò)展

兩個(gè)用法:用于重寫一些不可變類型數(shù)據(jù)的類如:str,int,tuple;元類?????

八、類的魔法方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容