初學 Python,對 object 和 type 的理解

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,因此aDog 類實際上是一回事兒,它們都是一個“類”,因此它們的__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,不捨晝夜。

希望能夠幫到初學者,同時歡迎批評指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章