はじめに
このセクションでは、メソッド定義と組み合わせて使用されるいくつかの組み込みデコレータについて説明します。
This tutorial is from open-source community. Access the source code
💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください
このセクションでは、メソッド定義と組み合わせて使用されるいくつかの組み込みデコレータについて説明します。
クラス定義において特別な種類のメソッドを指定するために使用される事前定義済みのデコレータがあります。
class Foo:
def bar(self,a):
...
@staticmethod
def spam(a):
...
@classmethod
def grok(cls,a):
...
@property
def name(self):
...
順に見ていきましょう。
@staticmethod
は、いわゆる 静的 クラスメソッド(C++/Java 由来)を定義するために使用されます。静的メソッドは、クラスの一部である関数ですが、インスタンスに対しては動作しません。
class Foo(object):
@staticmethod
def bar(x):
print('x =', x)
>>> Foo.bar(2) ## x=2
>>>
静的メソッドは、時々、クラスの内部サポートコードを実装するために使用されます。たとえば、作成されたインスタンスを管理するコード(メモリ管理、システムリソース、永続化、ロックなど)です。また、特定のデザインパターン(ここでは説明しません)によっても使用されます。
@classmethod
は、クラスメソッドを定義するために使用されます。クラスメソッドは、インスタンスではなく、クラス オブジェクトを最初のパラメータとして受け取るメソッドです。
class Foo:
def bar(self):
print(self)
@classmethod
def spam(cls):
print(cls)
>>> f = Foo()
>>> f.bar()
<__main__.Foo object at 0x971690> ## インスタンス `f`
>>> Foo.spam()
<class '__main__.Foo'> ## クラス `Foo`
>>>
クラスメソッドは、主に代替コンストラクタを定義するためのツールとして使用されます。
class Date:
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
@classmethod
def today(cls):
## クラスが引数として渡される方法に注意
tm = time.localtime()
## そして新しいインスタンスを作成するために使用される
return cls(tm.tm_year, tm.tm_mon, tm.tm_mday)
d = Date.today()
クラスメソッドは、継承などの機能に関するいくつかの難しい問題を解決します。
class Date:
...
@classmethod
def today(cls):
## 正しいクラス(たとえば `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
プログラムにはこのようなコードがあります:
def read_portfolio(filename, **opts):
'''
株式ポートフォリオファイルを、name、shares、および 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('portfolio.csv') as lines:
... port = Portfolio.from_csv(lines)
...
>>>
Portfolio
クラスにこれらの変更を加え、report.py
コードを修正してクラスメソッドを使うようにしましょう。
おめでとうございます!あなたはデコレートされたメソッドの実験を完了しました。あなたの技術を向上させるために、LabEx でさらに多くの実験を行って練習してください。