目錄 | 上一節 (7.4 裝飾器) | 下一節 (8 測試和調試)html
本節討論一些與方法定義結合使用的內置裝飾器。python
在類定義中,有許多預約義的裝飾器用於指定特殊類型的方法。git
class Foo: def bar(self,a): ... @staticmethod def spam(a): ... @classmethod def grok(cls,a): ... @property def name(self): ...
讓咱們逐個查看吧。github
@staticmethod
用於定義所謂的靜態類方法( static class method,來自於 C++/Java)。靜態方法是一個函數,這個函數是類的一部分,但不是在實例上進行操做。設計模式
class Foo(object): @staticmethod def bar(x): print('x =', x) >>> Foo.bar(2) x=2 >>>
靜態方法有時用於實現類的內部支持代碼,例如,用於幫助管理已建立的實例(內存管理,系統資源,持久化,鎖等等)。有時也用於某些設計模式(這裏暫不討論)。app
@classmethod
用於定義類方法(class methods)。類方法是一種將 類 對象而不是實例做爲第一個參數的方法。函數
class Foo: def bar(self): print(self) @classmethod def spam(cls): print(cls) >>> f = Foo() >>> f.bar() <__main__.Foo object at 0x971690> # The instance `f` >>> Foo.spam() <class '__main__.Foo'> # The class `Foo` >>>
類方法經常使用做定義替代構造函數(constructor)的工具。工具
import time class Date: def __init__(self,year,month,day): self.year = year self.month = month self.day = day @classmethod def today(cls): # Notice how the class is passed as an argument tm = time.localtime() # And used to create a new instance return cls(tm.tm_year, tm.tm_mon, tm.tm_mday) d = Date.today()
類方法能夠和繼承等特性一塊兒使用以解決棘手的問題。測試
class Date: ... @classmethod def today(cls): # Gets the correct class (e.g. `NewDate`) tm = time.localtime() return cls(tm.tm_year, tm.tm_mon, tm.tm_mday) class NewDate(Date): ... d = NewDate.today()
在 report.py
和 portfolio.py
文件中, Portfolio
類的建立稍微有點混亂。例如,report.py
程序具備以下代碼:spa
def read_portfolio(filename, **opts): ''' Read a stock portfolio file into a list of dictionaries with keys name, shares, and price. ''' with open(filename) as lines: portdicts = fileparse.parse_csv(lines, select=['name','shares','price'], types=[str,int,float], **opts) portfolio = [ Stock(**d) for d in portdicts ] return Portfolio(portfolio)
且 portfolio.py
文件中定義的 Portfolio
具備一個奇怪的初始化:
class Portfolio: def __init__(self, holdings): self.holdings = holdings ...
坦白說,由於代碼分散在各文件中,因此責任鏈稍微有點混亂。若是 Portfolio
類應該包含 Stock
類的實例列表,那麼你應該修改該類以使其更清晰。示例:
# portfolio.py import stock class Portfolio: def __init__(self): self.holdings = [] def append(self, holding): if not isinstance(holding, stock.Stock): raise TypeError('Expected a Stock instance') self.holdings.append(holding) ...
若是想要從 CSV 文件中讀取投資組合數據,那麼你也許應該爲此建立一個類方法:
# portfolio.py import fileparse import stock class Portfolio: def __init__(self): self.holdings = [] def append(self, holding): if not isinstance(holding, stock.Stock): raise TypeError('Expected a Stock instance') self.holdings.append(holding) @classmethod def from_csv(cls, lines, **opts): self = cls() portdicts = fileparse.parse_csv(lines, select=['name','shares','price'], types=[str,int,float], **opts) for d in portdicts: self.append(stock.Stock(**d)) return self
要使用新的 Portfolio 類,你能夠這樣編寫代碼:
>>> from portfolio import Portfolio >>> with open('Data/portfolio.csv') as lines: ... port = Portfolio.from_csv(lines) ... >>>
請對 Portfolio
類進行修改,而後修改 report.py
的代碼以使用類方法。