mywang88
2018-04-14
0 簡介
初學 Python,發現 Python 中關於類、實例(對象)、Object等概念有一個很系統、很嚴密的邏輯體系。
但對於初學者也存在一些容易產生歧義的問題,特此整理。
附 Python 官方文檔地址:https://docs.python.org/3/
1 理解
1.1 常見的類
在 Python 編程中,人們習慣用首字母大寫的單詞來命名一個類。但是這也不是絕對的,很多系統的內置類型就都是小寫字母開頭的:
- str 類:字符串類
- int 類:整數類
- float 類:浮點數類
- list 類:列表類
- dict 類:字典類
- tuple 類:元組類
- set 類:集合類
上述的幾種類是 Python 的數據結構的主要組成部分,也都相對直觀,易於理解。但從某個特殊的 Python 版本開始,爲了使 Python 的整個體系變得更加系統和嚴密,開發者們爲 Python 新增加了幾個重要的內置類型。
# 題外話:
# 最早很好使用微積分的人,是萊布尼茨和牛頓。但在那時,“極限”甚至都還沒有嚴格的數學定義。
# 最終,使微積分的理論變得系統和嚴密的,是後來的高斯、柯西等一系列數學家。
本文關注的,是以下兩個內置類型:
- type 類:類型類,所有的類都屬於 type 類。換言之,每一個類,都是 type 類的一個實例(對象)
- object 類:應該被翻譯爲“對象”,或者“東西”類。object 類是所有類的父類。換言之,其它的任何一個類,都直接或間接地繼承了 object 類(的屬性和方法)。
1.2 定義一個類
爲了便於下文的分析,我們先來定義一個最簡單的類。
# 定義犬類
class Dog:
# 不創建任何屬性和方法
pass
a = Dog
print(a)
b = Dog()
print(b)
這裏定義了一個類:Dog 類。
執行代碼,將得到:
<class ‘main.Dog’>
<main.Dog object at 0x00000201CD043198>
值得注意的是:
a = Dog
實際上是將Dog 類
賦值給了變量a
,因此,a
是一個類
b = Dog()
實際上是爲Dog 類
創建了一個實例(對象),即b
屬於Dog 類
,換句話說,b
是一條狗。
因此,它們的打印結果是不同的,因爲它們本就完全不同。
__main__.
表示這個“犬類”是在本模塊內部定義的。
1.3 type 類
一個類就是一個類,所有的類都屬於“類”這個類,即type 類
。
對於 Python 中的任何一個對象(或者說“東西”),它都有一個名爲__class__
的屬性,這個屬性的值就是該對象所屬於的類。屬性名稱前後各有兩條下劃線,這意味着這個屬性是 Python 的內置(built-in)屬性,下劃線是不可以被省略的。
例如:
class Dog:
pass
a = Dog
print(a.__class__)
print(Dog.class)
b = Dog()
print(b.__class__)
print(b.__class__ == Dog)
執行,結果爲:
<class ‘type’>
<class ‘type’>
<class ‘main.Dog’>
True
我們把Dog 類
賦值給變量a
,因此a
和Dog 類
實際上是一回事兒,它們都是一個“類”,因此它們的__class__
屬性的值爲type 類
。
我們爲Dog 類
創建了實例(對象)b
,因此,b
的__class__
屬性的值就是Dog 類
。
需要注意的是,__class__
屬性的值並不是一個字符串,它真的就是一個類,也就是type 類
的一個實例(對象),print(b.__class__ == Dog)
語句打印出 True 正是爲了說明這一點。
1.4 type() 函數
type()
函數是一個筆者忍不住要吐槽的函數,它很容易使初學者產生誤解。本文篇幅有限,只做簡要分析。
type()
函數與type 類
是重名的,但它們不是一個東西,當單詞 type 後面帶有括號的時候,它代表的是一個名爲 type 的函數。
當type()
函數的括號裏只有一個參數的時候,type
函數的返回(return)的值是該參數所屬於的類,即返回值是一個type 類
的實例(對象)。
因此,對於一個變量v1
來說,它的內置屬性__class__
的值:v1.__class__
,與將該變量傳遞給type()
函數,獲得的返回值type(v1)
實際上是一回事。二者都是v1
所屬於的類:
class Dog:
pass
v1 = Dog()
print(type(v1))
print(v1.__class__)
實際上,除了type 類
以外,Python 的其它內置類型往往也對應了與之重名的函數。
例如,str 類
對應了str()
函數,這個函數的作用是,將傳入的參數轉化爲一個字符串,即一個str 類
的實例對象。
Python 在這裏相當於爲同一件事情提供了兩種不同的方法,或者說角度,引用內置屬性,例如__class__
,的方法更符合“面向對象”編程的思路。
1.5 object 類
前文提到,object 這個單詞可以譯爲“對象”,或者“東西”。
那麼如何來理解“object類是所有類的父類”這句話呢?
通俗地說:一條狗屬於犬類,這條狗也屬於動物類,犬類是動物類的一個分支,換句話說,犬類是動物類的“子類”,動物類是犬類的“父類”。
更進一步:一條狗屬於犬類,這條狗也是一個“對象”,或者說“東西”。不管是一條狗,還是一瓶飲料,它們從廣義上(本質上)來說都是一個“東西”。因此,“東西”類,即object 類
,也就是所有type 類
的實例(對象)的父類。
一個類的內置屬性__bases__
的值是由該類的父類組成的一個元組。
class Dog:
pass
# Dog類 是type類的一個實例
print(Dog.__class__)
# Dog類 是object類的一個子類
print(Dog.__bases__)
# type類 是一個廣義的“東西” 因此也是object類的一個子類
print(type.__bases__)
# object類 是一個類 因此也是type類的一個實例
print(object.__class__)
運行腳本,結果如下:
<class ‘type’>
(<class ‘object’>,)
(<class ‘object’>,)
<class ‘type’>
# 題外話:
# 從唯物的角度,object可理解爲“客觀的存在”
# 從唯心的角度,object可理解爲“感知的對象”
# 要舉出一個不是“客觀的存在”或者“感知的對象”的例子似乎不是那麼容易...
1.6 補充
- type() 函數的參數也可以爲 3 個,這一情形不在本文討論範圍內。
- 在創建一個類的實例的時候,
a = Dog()
的類名後邊也是有括號的,一般來說這意味着調用該類的內置方法(method)__init__()
。
2 小結
筆者初學 Python 時,版本號還是 3.6,回過頭來重新修訂這篇博客的時候,版本號已經是 3.7 了。
逝者如 Python,不捨晝夜。
希望能夠幫到初學者,同時歡迎批評指正。