前面一篇文章介紹了一些Python物件的基本概念,這篇接著來看看Python物件相關的一些內容。
Python物件的比較
Python物件有三個要素:身份,型別和值,所以我們就分別從這三個角度出發看看物件之間的比較。
物件身份比較
物件身份的比較,其實就是比較物件的記憶體地址,即內建函式id()的結果比較。可以用來判斷不同的變數是否指向了同一個地址。
直接看例子:
通過例子的輸出可以得到,f1和f2指向了不同的物件(地址);但是,i1和i2卻指向了相同的物件(地址)。
之所以產生這種差異,是因為Python對整數物件和字串物件會進行快取,所以沒有產生新的物件,而是指向了快取的物件。不同版本的Python處理快取是不一樣的,所以同樣的例子可能產生不同的結果。
對於物件身份比較,還可以使用Python中的”is”關鍵字:
1 2 3 4 5 6 7 |
obj1 is obj2 # 等價 id(obj1) == id(obj2) obj1 is not obj2 # 等價 id(obj1) != id(obj2) |
物件型別比較
通過type()內建函式,可以得到一個物件的型別,然後就可以進行型別比較了。
看一段程式碼:
例子中使用了三種方式進行物件型別的比較:
- 直接將type(obj)與型別進行比較
- 將type(obj)的身份跟型別的身份進行比較
- 通過內建的isinstance()函式,判斷一個物件是不是有特定型別例項化得到的
- 其第一個引數為物件,第二個為型別名或型別名的一個列表
- 其返回值為布林型
簡單看看前兩種方式的區別,第一種方式是直接將兩個型別物件的值進行比較;而第二種方式比較的是兩個型別物件的身份,這種方式的原理是,如果兩個型別物件的身份不同,那麼兩個型別物件的值肯定不同。
物件值比較
對於Python物件,可以直接使用比較操作符(>,<,==等)進行物件值的比較。關於Python的內建物件,有一套比較規則,比如兩個list物件的比較就是按照list比較規則進行的。
這裡我們就主要看看自定義型別的物件之間的比較。
自定義型別的物件值比較
在Python中,所有的型別都有一套用於比較的”魔術方法” ,對於自定義的型別,我們就可以通過實現這些方法來定義自定義型別的物件的比較行為:
- __cmp__(self, other) : __cmp__ is the most basic of the comparison magic methods. __cmp__ should return a negative integer if self < other, zero if self == other, and positive if self > other.
- __eq__(self, other) Defines behavior for the equality operator, ==.
- __ne__(self, other) Defines behavior for the inequality operator, !=.
- __lt__(self, other) Defines behavior for the less-than operator, <.
- __gt__(self, other) Defines behavior for the greater-than operator, >.
- __le__(self, other) Defines behavior for the less-than-or-equal-to operator, <=.
- __ge__(self, other) Defines behavior for the greater-than-or-equal-to operator, >=.
看一個例子,我們定義了一個”語句”型別,並實現了一些比較方法,這樣對於改型別的物件,我們就可以直接通過比較操作符進行物件值比較了。
有一點需要注意的是,關於自定義型別的物件,如果沒有實現比較操作符對應的”魔術方法”,那麼將預設使用物件身份(id())進行比較。
“is”和”==”的差別
這裡需要注意一下”is”和”==”之間的差別:
- “is”用來比較物件的身份是否相等,也就是說,比較物件的記憶體地址是否相同(變數是否指向同一個物件)
- “==”用來比較物件的內容(值)是否相等
看下面的程式碼:
對於變數c和d,由於數值超過了Python對整型數的快取範圍,所有d就會是Python生成的一個新的物件。因此,c和d的值是相同的,但是身份卻是不同的。
可變物件和不可變物件
在Python中,一切都是物件,Python中不存在所謂的傳值,一切傳遞的都是物件的引用(也可以認為是傳址)。
上一篇文章中瞭解到,根據Python物件的型別,可以將Python物件分為:Type Object(型別物件)和Non-type Object(非型別物件)。
同樣,根據物件的可變性,也可以將Python物件分為兩類:可變(mutable)物件和不可變(immutable)物件。
- 不可變(immutable)物件:物件的內容不可變,當嘗試改變物件內容的時候,會建立一個新的物件;也就是說物件的身份(id())會發生變化
- 例如:number、string,tuple
- 可變(mutable)物件:物件的內容可變,當改變物件內容的時候,物件的身份(id())不會變化
- 例如:list、dict、set
看一段簡單的程式碼:
tuple是”可變的”
雖然元組物件本身是不可變的,但這並不意味著元組包含的可變物件也不可變。
看下面的例子:
現在我們根據下圖分析這段程式碼,tpl這個元組的第四個元素比較特殊,是一個list;所以,在tpl中第四個元素存放的是這個list的地址(身份id(),引用)。
元組的不可變性就決定了tpl第四個元素對應的內容,即list的地址不能改變了,但是,這個地址37865712指向的內容是可以被改變的。
總結
本篇介紹了Python物件的比較,包括物件的身份,型別以及值的比較。對於自定義型別的物件,如果需要進行比較操作,可以通過自定義比較操作相關的”魔術方法”。
另外,文中簡單介紹了Python物件的可變性,對比了可變(mutable)物件和不可變(immutable)物件之間的不同。