翻譯:《實用的Python編程》04_03_Special_methods
目錄 | 上一節 (4.2 繼承) | 下一節 (4.4 異常)
4.3 特殊方法
可以通過特殊方法(或者稱為"魔術"方法(magic method))自定義 Python 行為的各部分。本節介紹特殊方法的思想。此外,還將討論動態屬性訪問和綁定方法。
簡介
類可以定義特殊方法。特殊方法對于 Python 解釋器而言具有特殊的意義。特殊方法總是以雙下劃線 __ 開頭和結尾,例如 __init__。
class Stock(object):
def __init__(self):
...
def __repr__(self):
...
雖然有很多特殊方法,但是我們只研究幾個具體的例子。
字符串轉換的特殊方法
對象有兩種字符串表示形式。
>>> from datetime import date
>>> d = date(2012, 12, 21)
>>> print(d)
2012-12-21
>>> d
datetime.date(2012, 12, 21)
>>>
str() 函數用于創建格式良好的、可打印的輸出:
>>> str(d)
'2012-12-21'
>>>
repr() 函數用于創建詳細的、面向程序員的輸出。
>>> repr(d)
'datetime.date(2012, 12, 21)'
>>>
str() 和 repr() 函數都是使用類中定義的特殊方法生成要顯示的字符串。
class Date(object):
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
# Used with `str()`
def __str__(self):
return f'{self.year}-{self.month}-{self.day}'
# Used with `repr()`
def __repr__(self):
return f'Date({self.year},{self.month},{self.day})'
注意:按照慣例,__repr__() 返回一個字符串,當該字符串被傳遞給 eval() 函數,將會重新創建底層對象(譯注:eval(repr(obj)) == obj)。如果不行,則使用某種易于閱讀的表現形式。
數學操作的特殊方法
數學運算符涉及的特殊方法如下:
a + b a.__add__(b)
a - b a.__sub__(b)
a * b a.__mul__(b)
a / b a.__truediv__(b)
a // b a.__floordiv__(b)
a % b a.__mod__(b)
a << b a.__lshift__(b)
a >> b a.__rshift__(b)
a & b a.__and__(b)
a | b a.__or__(b)
a ^ b a.__xor__(b)
a ** b a.__pow__(b)
-a a.__neg__()
~a a.__invert__()
abs(a) a.__abs__()
元素訪問的特殊方法
這些是實現容器的特殊方法:
len(x) x.__len__()
x[a] x.__getitem__(a)
x[a] = v x.__setitem__(a,v)
del x[a] x.__delitem__(a)
你可以在類中使用這些特殊方法。
class Sequence:
def __len__(self):
...
def __getitem__(self,a):
...
def __setitem__(self,a,v):
...
def __delitem__(self,a):
...
方法調用
調用方法有兩個步驟。
? 1、查找:. 運算符
? 2、方法調用: () 運算符
>>> s = Stock('GOOG',100,490.10)
>>> c = s.cost # Lookup
>>> c
<bound method Stock.cost of <Stock object at 0x590d0>>
>>> c() # Method call
49010.0
>>>
綁定方法
尚未被函數調用運算符 () 調用的方法稱為綁定方法( 譯注:bound method,如果直譯應該譯作“綁定的方法”,但是,就像“類方法”一樣,可以省略“的”這個字,譯為“綁定方法”,綁定在這里不是動詞,而應理解為形容詞“綁定的”)。它對自己生成的實例進行操作:
>>> s = Stock('GOOG', 100, 490.10)
>>> s
<Stock object at 0x590d0>
>>> c = s.cost
>>> c
<bound method Stock.cost of <Stock object at 0x590d0>>
>>> c()
49010.0
>>>
如果使用綁定方法時有些大意,那么容易導致錯誤。示例:
>>> s = Stock('GOOG', 100, 490.10)
>>> print('Cost : %0.2f' % s.cost)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: float argument required
>>>
或者:
f = open(filename, 'w')
...
f.close # Oops, Didn't do anything at all. `f` still open.
在這兩種情形中,錯誤都是由忘記尾部括號引起的。例如:s.cost() or f.close()。
屬性訪問
還有一種訪問、操作和管理屬性的替代方法。
getattr(obj, 'name') # Same as obj.name
setattr(obj, 'name', value) # Same as obj.name = value
delattr(obj, 'name') # Same as del obj.name
hasattr(obj, 'name') # Tests if attribute exists
示例:
if hasattr(obj, 'x'):
x = getattr(obj, 'x'):
else:
x = None
注意: getattr() 函數的默認參數非常有用。
x = getattr(obj, 'x', None)
練習
練習 4.9:更好的輸出
請修改 stock.py 文件中定義的 Stock 對象,以便 __repr__() 方法生成更有用的輸出。示例:
>>> goog = Stock('GOOG', 100, 490.1)
>>> goog
Stock('GOOG', 100, 490.1)
>>>
修改完成后,請查看讀取股票投資組合時會發生什么,以及生成什么樣的結果。示例:
>>> import report
>>> portfolio = report.read_portfolio('Data/portfolio.csv')
>>> portfolio
... see what the output is ...
>>>
練習 4.10:使用 getattr() 的例子
getattr() 是讀取屬性的另一種機制。可以使用它編寫極其靈活的代碼。首先,請嘗試以下示例:
>>> import stock
>>> s = stock.Stock('GOOG', 100, 490.1)
>>> columns = ['name', 'shares']
>>> for colname in columns:
print(colname, '=', getattr(s, colname))
name = GOOG
shares = 100
>>>
仔細觀察會發現輸出數據完全由 columns 變量中列出的屬性名決定。
在 tableformat.py 文件中,使用該思想將其擴展為通用函數 print_table(),print_table()打印一個表格,顯示用戶指定的任意對象的屬性。與早期的 print_report() 函數一樣,print_table() 方法還應接受一個 TableFormatter 實例來控制輸出格式。它們的工作方式如下:
>>> import report
>>> portfolio = report.read_portfolio('Data/portfolio.csv')
>>> from tableformat import create_formatter, print_table
>>> formatter = create_formatter('txt')
>>> print_table(portfolio, ['name','shares'], formatter)
name shares
---------- ----------
AA 100
IBM 50
CAT 150
MSFT 200
GE 95
MSFT 50
IBM 100
>>> print_table(portfolio, ['name','shares','price'], formatter)
name shares price
---------- ---------- ----------
AA 100 32.2
IBM 50 91.1
CAT 150 83.44
MSFT 200 51.23
GE 95 40.37
MSFT 50 65.1
IBM 100 70.44
>>>
浙公網安備 33010602011771號