2.21. 方法與屬性¶
方法 是定義在類別內部的函式。它的第一個參數是該方法被呼叫於其上的實例;慣例上將它命名為 self。
2.21.1. 實例方法¶
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def magnitude(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
p = Point(3, 4)
print(p.magnitude())
輸出:
5.0
呼叫 p.magnitude() 會自動將 p 作為 self 傳入。方法主體透過 self 讀取並更新屬性,方式與函式透過參數讀取並更新名稱相同。
2.21.2. 實例屬性與類別屬性¶
指派給 self 的屬性 -- 通常在 __init__ 內部 -- 屬於那一個實例:
a = Point(1, 2)
b = Point(10, 20)
a.x = 99
print(a.x, b.x) # 99 10
a.x 與 b.x 是不同的儲存空間;變動其中一個並不會影響另一個。
在類別主體中、任何方法 之外 指派的名稱,則由該類別的每個實例共用:
class Counter:
kind = "tally" # class attribute -- shared
def __init__(self):
self.value = 0 # instance attribute -- per instance
a = Counter()
b = Counter()
print(a.kind, b.kind) # tally tally
類別屬性存在於類別本身且為共用。實例屬性則存在於各個實例上。¶
類別屬性的存取方式與實例屬性相同(a.kind);Python 會先在實例上尋找,再到類別上尋找。指派給 a.kind 會建立一個新的 實例 屬性,遮蔽掉類別的那個,而 b.kind 則不受影響。
對於每個實例都應以相同方式看待的常數與預設值,使用類別屬性。對於每個物件都應擁有自己一份副本的狀態,使用實例屬性。
2.21.3. __str__ 與 __repr__¶
有兩個特殊方法控制著實例如何列印。__str__ 回傳由 print() 使用的「友善」字串;__repr__ 則回傳在 REPL 中以及容器顯示內部使用的「開發者」字串:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return "(" + str(self.x) + ", " + str(self.y) + ")"
def __repr__(self):
return "Point(" + str(self.x) + ", " + str(self.y) + ")"
p = Point(3, 4)
print(p) # uses __str__
print([p, p]) # uses __repr__ inside the list
輸出:
(3, 4)
[Point(3, 4), Point(3, 4)]
如果只定義了 __repr__,print() 會退而使用它 -- 因此單單一個寫得好的 __repr__ 通常就夠了。唯有當友善形式應與開發者形式看起來不同時,才一併定義 __str__。盡量讓 __repr__ 看起來像是能重新建立該物件的呼叫;當列印出的值明確無歧義時,除錯會變得輕鬆許多。