<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我們前面其實已經接觸過封裝的概念,把亂七八糟的資料扔進列表裡面,這是一種封裝,是資料層面的封裝;把常用的程式碼段打包成一個函數,這也是一種封裝,是語句層面的封裝;現在我們要學習的物件,也是一種封裝的思想, 物件的來源是模擬真是世界,將資料和程式碼都封裝在了一起。
打個比方,烏龜就是真實世界的一個物件,通常會從兩個部分來描述它。
(1)從靜態的特徵描述:例如,綠色的,有四條腿,有外殼等等,這是靜態一方面的描述。
(2)從動態的行為描述:例如,它會爬,如果追它,它還會跑,有時還會咬人,睡覺等等,這都是從行為方面進行描述的。
Python中的物件也是如此,一個物件的特徵稱為“屬性”,一個物件的行為稱為“方法”。:
如果將烏龜寫成程式碼,將會是下面這樣:
class Turtle: # Python中的類名約定以大寫字母開頭 # 特徵的描述稱為屬性,在程式碼層面看來其實就是變數 color = 'green' legs = 4 shell = True # 方法實際就是函數,通過呼叫這些函數來完成某些工作 def climb(self): print('向前爬') def run(self): print('向前跑') def bite(self): print('咬人') def sleep(self): print('睡覺')
以上程式碼定義了物件的特徵(屬性)和行為(方法),但還不是一個完整的物件,將定義的這些稱為類(Class)。需要使用類來建立一個真正的物件,這個物件就叫作這個類的一個範例(Instance),也叫範例物件(Instance Objects)。
舉個例子,這就像工廠需要生產一系列玩具,需要先作出這個玩具的模具,然後根據這個模具再進行批次生產。
那麼怎麼建立真正的範例物件呢?建立一個物件,也叫類的範例化,其實很簡單:
# 首先要有上面那一段類的定義 tt = Turtle()
注意:類名後面跟著小括號,這跟呼叫函數是一樣的。所以在Python中,類名約定用大寫字母開頭,函數用小寫字母開頭,這樣更容易區分。另外,賦值操作並不是必需的,但如果沒有把建立好的範例物件賦值給一個變數,這個物件就沒辦法使用,因為沒有參照指向這個範例,最終會被Python的垃圾回收機制自動回收。
如果要 呼叫物件裡的方法,使用點操作符(.) 即可。
接下來我們看一段程式碼,再深入理解一下類、類物件和範例物件三個概念:
從這個例子可以看出,對範例物件c的count屬性進行賦值後,就相當於覆蓋了類物件C的count屬性。如下圖所示,如果沒有賦值覆蓋,那麼參照的是類物件的count屬性。
需要注意的是,類中定義的屬性是靜態變數,類的屬性是與類物件進行繫結,並不會依賴任何它的範例物件。
另外,如果屬性的名字跟方法名相同,屬性會覆蓋方法:
為了避免名字上的衝突,應該遵守一些約定俗成的規矩:
(1)不要試圖在一個類裡面定義出所有能想到的特性和方法,應該利用繼承和組合機制進行擴充套件。
(2)用不同的詞性命名,如屬性名用名詞、方法名用動詞,並使用駝峰命名法等。
細心的讀者發現物件的方法都會有一個self引數,那麼這個self是什麼呢?如果你接觸過C++,那麼你應該很容易對號入座,Python的self其實就相當於C++的this指標。
如果你此前沒有接觸過任何程式語言,那麼簡單說,如果把類比作圖紙,那麼由類範例化後的物件才是真正可以住的房子。根據一張圖紙可以設計出成千上萬的房子,它們外觀都差不多,但是每一個房子都有不同的主人。每個人要找到自己的房子,那self就相當於這裡的門牌號,有了self,你就可以輕鬆找到自己的房子。
Python的self引數就是同一個道理,由一個類可以生成無數個物件,當一個物件方法被呼叫的時候,物件會將自身的參照作為第一個引數傳給該方法,那麼Python就知道需要操作哪個物件的方法了。
舉個簡單的例子:
一般物件導向的程式語言都會區分公有和私有的資料型別,像C++和Java它們使用public和private關鍵字用於宣告資料是公有的還是私有的,但在Python中並沒有類似的關鍵字來修飾。
預設上物件的屬性和方法都是公開的,可以直接通過點操作符(.)進行存取:
為了實現類似私有變數的特徵,Python內部採用了一種叫name mangling(名字改編)的技術,在Python中定義私有變數只需要在變數名或函數名前加上“_ _”兩個下劃線,那麼這個函數或變數就會成為私有的了:
這樣,在外部將變數名“隱藏”起來了,理論上如果要存取,就要從內部進行:
但是認真想一下這個技術的名字name mangling(名字改編),那就不難發現其實Python只是把雙下橫線開頭的變數進行了改名而已。實際上,在外部使用“_類名_ _變數名”即可存取雙下橫線開頭的私有變數了:
說明:Python目前的私有機制其實是偽私有的,Python的類是沒有許可權控制的,所有的變數都是可以被外部呼叫的。
舉個例子來說明繼承。例如現在有個遊戲,需要對魚類進行細分,有金魚(Goldfish)、鯉魚(Carp)、三文魚(Salmon)以及鯊魚(Shark)。那麼我們能不能不要每次都從頭到尾去重新定義一個新的魚類呢?因為我們知道大多數魚的屬性和方法是相似的,如果有一種機制可以讓這些相似的東西得以自動傳遞,那麼就方便多了。這就是繼承。
繼承的語法很簡單:
c l a s s 類 名 ( 被 繼 承 的 類 ) : . . . class 類名(被繼承的類): \ quad ... class類名(被繼承的類):...
被繼承的類稱為基礎類別、父類別或超類;繼承者稱為子類,一個子類可以繼承它的父類別的任何屬性和方法。
舉個例子:
需要注意的是,如果子類中定義與父類別同名的方法或屬性,則會自動覆蓋父類別對應的方法或屬性:
接下來,嘗試寫一下開頭提到的金魚(Goldfish)、鯉魚(Carp)、三文魚(Salmon)以及鯊魚(Shark)的例子。
import random as r class Fish: def __init__(self): self.x = r.randint(0, 10) self.y = r.randint(0, 10) def move(self): # 這裡主要演示類的繼承機制,就不考慮檢查場景邊界和移動方向問題 # 假設所有的魚都是一路向西遊 self.x -= 1 print("我的位置是:", self.x, self.y) # 金魚 class Goldfish(Fish): pass # 鯉魚 class Carp(Fish): pass #三文魚 class Salmon(Fish): pass # 上面三種魚都是食物,直接繼承Fish類的全部屬性和方法 # 下面定義鯊魚類,除了繼承Fish類的屬性和方法,還要新增一個吃的方法 class Shark(Fish): def __init__(self): self.hungry = True def eat(self): if self.hungry: print("吃掉你!") self.hungry = False else: print("太飽了,吃不下了~")
首先執行這段程式碼,然後進行測試:
同樣是繼承於Fish類,為什麼金魚(goldfish)可以移動,而鯊魚(shark)一移動就報錯呢?
可以看到報錯提示為:Shark物件沒有x屬性,這是因為在Shark類中,重寫了_ _init_ _()方法,但新的_ _init_ _()方法裡面沒有初始化鯊魚的x座標和y座標,因此呼叫move()方法就會出錯。
那麼解決這個問題,只要在鯊魚類中重寫_ _init_ _()方法的時候先呼叫基礎類別Fish的_ _init_ _()方法。
下面介紹兩種可以實現的技術:
什麼是呼叫未繫結的父類別方法?舉個例子:
修改之後,再執行下發現鯊魚也可以成功移動了:
這裡需要注意的是,這個self並不是父類別Fish的範例物件,而是子類Shark的範例物件。所以這裡說的未繫結是指並不需要繫結父類別的範例物件,使用子類的範例物件代替即可。
super函數能夠幫助我們自動找到基礎類別的方法,而且還為我們傳入了self引數,這樣就不需要做這些事情了:
執行後得到同樣的結果:
除此之外,Python還支援多重繼承,就是可以同時繼承多個父類別的屬性和方法:
c l a s s 類 名 ( 父 類 1 , 父 類 2 , 父 類 3 , . . . ) : . . . class 類名(父類別1,父類別2,父類別3,...):\ quad ... class類名(父類別1,父類別2,父類別3,...):...
舉個例子:
這就是基本的多重繼承語法,但多重繼承很容易導致程式碼混亂,所以當你不確定是否真的必須使用多重繼承的時候,請儘量避免使用它,因為有些時候會出現不可預見的BUG。
前面學習了繼承的概念,又提到了多重繼承,但如果現在我們有了烏龜類、魚類,現在要求定義一個類,叫水池,水池裡要有烏龜和魚。用多重繼承就顯得很奇怪,因為水池和烏龜、魚是不同物種,那怎樣把它們組合成一個水池的類呢?
其實在Python中很簡單,直接把需要的類放進去範例化就可以了,這就叫組合:
先執行上段程式碼,然後測試:
Python的物件有許多神奇的方法,如果你的物件實現了這些方法中的某一個,那麼這個方法就會在特殊情況下被Python所呼叫,而這一切都是自動發生的。
通常把_ _init_ _()方法稱為構造方法,只要範例化一個物件,這個方法就會在物件被建立時自動呼叫。範例化物件時是可以傳入引數的,這些引數會自動傳入_ _init_ _()方法中,可以通過重寫這個方法來自定義物件的初始化操作。
舉個例子:
有些讀者可能會問,有些時候在類定義時寫_ _init_ _()方法,有時候卻沒有,這是為什麼呢?看下面這個例子:
這裡需要注意的是,_ _init_ _()方法的返回值一定是None,不能是其他:
所以,一般在需要進行初始化的時候才重寫_ _init_ _()方法。所以這個_ _init_ _()方法並不是範例化物件時第一個被呼叫的方法。
_ _new_ _()方法才是一個物件範例化的時候所呼叫的第一個方法。與其他方法不同的是,它的第一個引數不是self而是這個類(cls),而其他的引數會直接傳遞給_ _init_ _()方法的。
_ _new_ _()方法需要返回一個範例物件,通常是cls這個類範例化的物件,當然你也可以返回其他物件。
_ _new_ _()方法平時很少去重寫它,一般讓Python用預設的方案執行即可。但是有一種情況需要重寫這個方法,就是當繼承一個不可變的型別的時候,它的特性就顯得尤為重要了。
如果說_ _init_ _()和_ _new_ _()方法是物件的構造器的話,那麼Python也提供了一個解構器,叫作_ _del_ _()方法。當物件將要被銷燬的時候,這個方法就會被呼叫。但是需要注意的是,並非 del x 就相當於自動呼叫 x._ _del_ _(),_ _del_ _()方法是當垃圾回收機制回收這個物件的時候呼叫的。 舉個例子:
前面提到過繫結的概念,那到底什麼是繫結呢?Python中嚴格要求了方法需要有範例才能被呼叫,這種限制其實就是Python所謂的繫結概念。
有人可能會這麼嘗試,而且發現也可以呼叫:
但是,這樣做會有一個問題,就是根據類範例化後的物件根本無法呼叫裡面的函數:
實際上是由於Python的繫結機制,這裡自動把bb物件作為第一個引數傳入,所以才會出現TypeError。
再看一個例子:
_ _dict_ _屬性是由一個字典組成,字典中僅有範例物件的屬性,不顯示類屬性和特殊屬性,鍵表示的是屬性名,值表示屬性相應的資料值。
現在範例物件dd有了兩個新屬性,而且這兩個屬性是僅屬於範例物件的:
為什麼會這樣?其實這完全歸功於self引數:當範例物件dd去呼叫setXY方法的時候,它傳入的第一個引數就是dd,那麼self.x = 4, self.y = 5也就相當於dd.x = 4, dd.y = 5,所以在範例物件,甚至類物件中都看不到x和y,是因為這兩個屬性是隻屬於範例物件dd的。
如果把類範例刪掉,範例物件dd還能否呼叫printXY方法?答案是可以的:
到此這篇關於Python 類和物件詳細介紹的文章就介紹到這了,更多相關Python 類和物件內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45