【練習題】第十五章--類和物件(Think Python)
別名有可能讓程式讀起來有困難,因為在一個位置做出的修改有可能導致另外一個位置發生不可預知的情況。這樣也很難去追蹤指向一個物件的所有變數。所以就可以不用別名,而用複製物件的方法。copy 模組包含了一個名叫 copy 的函式,可以複製任意物件:
>>> p1 = Point()
>>> p1.x = 3.0
>>> p1.y = 4.0
>>> import copy
>>> p2 = copy.copy(p1)
p1和 p2包含的資料是相同的,但並不是同一個點物件。
>>> print_point(p1) (3, 4) >>> print_point(p2) (3, 4) >>> p1 is p2 False >>> p1 == p2 False
is 運算子表明 p1和 p2不是同一個物件,這就是我們所預料的。但你可能本想著是==運算子應該得到的是 True 因為這兩個點包含的資料是一樣的。這樣的話你就會很失望地發現對於例項來說,==運算子的預設行為就跟 is 運算子是一樣的;它也還是檢查物件的身份,而不是物件的相等性。這是因為你用的是使用者自定義的型別,Python 不值得如何去衡量是否相等。至少是現在還不能。
(譯者注:==運算子的實現需要運算子過載,也就是多型的一種,來實現,也就是對使用者自定義型別,需要使用者自定義運算子,而不能簡單地繼續用內建運算子。因為自定義型別的運算是 Python 沒法確定的,得使用者自己來確定。)
如果你用 copy.copy 複製了一個矩形,你會發現該函式複製了矩形物件,但沒有複製內嵌的點物件,所以裡面點的指向是同一個物件。
>>> box2 = copy.copy(box)
>>> box2 is box
False
>>> box2.corner is box.corner
True
這種運算叫做淺複製,因為複製了物件與物件內包含的所有引用,但不復制內嵌的物件。
所幸的是 copy 模組還提供了一個名為 deepcopy (深複製)的方法,這樣就能把內嵌的物件也複製了。你肯定不會奇怪了,這種運算就叫深複製了。
>>> box3 = copy.deepcopy(box)
>>> box3 is box
False
>>> box3.corner is box.corner
False
box3和 box 就是完全隔絕開,沒有公用內嵌物件,徹底不會相互干擾的兩個物件了。
除錯:
當你開始使用物件的時候,你就容易遇到一些新的異常。如果你試圖讀取一個不存在的屬性,就會得到一個屬性錯誤AttributeError:
>>> p = Point()
>>> p.x = 3
>>> p.y = 4
>>> p.z
AttributeError: Point instance has no attribute 'z'
如果不確定一個物件是什麼型別,可以『問』一下:
>>> type(p)
<class '__main__.Point'>
還可以用 isinstance 函式來檢查一下一個物件是否為某一個類的例項:
>>> isinstance(p, Point)
True
如果不確定某一物件是否有一個特定的屬性,可以用內建函式 hasattr:
>>> hasattr(p, 'x')
True
>>> hasattr(p, 'z')
False
hasattr 的第一個引數可以是任意一個物件;第二個引數是一個字串,就是要判斷是否存在的屬性名字。
用 try 語句也可以試驗一個物件是否有你需要的屬性:
try:
x = p.x
except AttributeError:
x = 0