最近、Python言語機能に特化した本を読んでいました(この記事の内容の一部は** Fluent Python **という本からのものです)。データモデルという言葉が本の中で言及されています。データモデルは私たちがよく言うことですか?データの種類は?実際にはそうではありません。データモデルはPythonフレームワークの記述であり、独自のビルディングブロックのインターフェイスを規制します。これらのインターフェイスは、 __iter__
、 __len__
、 __del__
などのPythonの特別なメソッドとして理解できます。これらのモジュールには、シーケンス、イテレーター、関数、クラス、およびコンテキストマネージャーが含まれますが、これらに限定されません。オブジェクトのどのメソッドとプロパティをシーケンスと呼ぶことができるかについて議論している場合、実際には、シーケンスのデータモデルについて議論しています。
**Pythonの最高の品質の1つは一貫性です。一定期間Pythonを使用すると、Python言語を理解し始め、新しい言語機能を正しく推測できるようになります。 ****
他のプログラミング言語の経験を持つPythonを使用している場合は、 object.len()
ではなく len(object)
に興味があるかもしれません。 Java
言語では、object.len()
がよく使用されます。このメソッドは、オブジェクトの長さを取得します。 この不快感の背後にある力をさらに理解すると、PythonデータモデルのAPIであるPythonデータモデルを構築した結果であるPythonの設計哲学に納得するでしょう。本物のPython機能を使用してオブジェクトを構築すると、ツールが提供されます。これは、 ** Pythonic **
**と呼ばれることがよくあります。 ****
どのフレームワークを記述しても、フレームワーク自体によって呼び出されるメソッドを実装するために多くの時間を費やします。Pythonフレームワーク自体も例外ではありません。 object [item]
を使用している場合、実際にはバックグラウンドでメソッド object .__ getitem__
を呼び出します。これの利点は何ですか。自分で作成したオブジェクトで []
演算子を使用できるようにするために、クラスで __getitem__
メソッドを定義するだけで済みます。
__ getitem__
はPythonの特別なメソッドの1つです。一般的な特別なメソッドには、 __len__
、 __iter__
、 __enter__
、 __call__
などがあります。
これらの特別なメソッドを使用すると、独自のオブジェクトで次の言語アーキテクチャを実装およびサポートし、それらと対話できます。
データモデルは、Python言語機能を使用してオブジェクトを構築するためのAPIを提供するため、独自のシーケンスクラスを実装しようとしています。
classMyList(object):
def __init__(self,):
self.items =[str(x)for x inrange(10)]
self.len =10
def __getitem__(self, item):return self.items[item]
def __len__(self):return self.len
a =MyList()for x in a:print(x)print('最初の要素', a[0])print("長さ:",len(a))
自己定義クラスは、反復、スライス、および len
メソッドをサポートします。これは、実際にはPythonシーケンスを実装するプロトコル(非公式インターフェイス)です。組み込みのサブクラス化ではなく、データモデルを介してカスタムシーケンスを実装しました。実際にはアヒルモデルの言語であるシーケンスは、特定のクラスがアヒルのように動作する場合(ここではシーケンスを指します)、このクラスはシーケンスであると言えます。サブクラス化またはシリアルプロトコルのどちらで達成されるかは関係ありません。
特別なメソッドを使用することで、Pythonデータモデルを使用する利点をすでに理解できます。クラスのユーザーとして、標準操作のさまざまな名前(「長さを取得する方法」)を覚えておく必要はありません。.size()または.length( ) または、他の何か?)
上記の例では、 MyList
クラスを繰り返してスライスすることができます。スライスの機能は、 __getitem__
によって提供され、繰り返しの機能は、実際には、繰り返し可能なオブジェクトを返す __iter__
によって提供されます。しかし、 MyList
クラスには __iter__
メソッドがありません。何が起こっているのでしょうか。
__iter__
メソッドが実装されていないが、 __getitem__
メソッドが実装されている場合、Pythonはイテレーターを作成し、要素を順番に取得しようとします(インデックス0から開始)。
ここで、 a
オブジェクトを印刷しようとします
classMyList(object):
def __init__(self,):
self.items =[str(x)for x inrange(10)]
self.len =10
def __getitem__(self, item):return self.items[item]
def __len__(self):return self.len
a =MyList()print(a)
>><__ main__.MyList object at 0x0000015AEAFC95F8>
その結果、私たちが気にしない一連のメモリアドレスが生成されますが、オブジェクトを直接印刷すると、一部のPython組み込みモジュールまたはサードパーティライブラリが、このようにではなく、理解できる情報になることがよくあります。メモリアドレス。
実際、これは文字列を返す特別なメソッド __str__
によって実現できます。これは、特別なメソッド __str__
を MyList
クラスに追加することで実現できます。
classMyList(object):
def __init__(self,):
self.items =[str(x)for x inrange(10)]
self.len =10
def __getitem__(self, item):return self.items[item]
def __len__(self):return self.len
def __str__(self):return','.join(self.items)
a =MyList()print(a)
>>0,1,2,3,4,5,6,7,8,9
xが組み込み型のインスタンスである場合、len(x)は非常に高速になります。その背後にある理由は、CPythonがメソッドをまったく呼び出さずにC構造からオブジェクトの長さを直接読み取るためです。コレクション内の要素の数を取得することは非常に一般的な操作です。この操作は、str、list、memoryview、およびその他のタイプに対して効率的である必要があります。言い換えれば、lenが通常の方法ではない理由は、Python自身のデータ構造がバックドアを通過できるようにするためであり、absについても同じことが言えます。しかし、その特別な方法のおかげで、カスタムデータタイプにlenを使用することもできます。このアプローチは、組み込み型の効率を維持することと言語の一貫性を確保することのバランスを見つけ、「Python」の別の文を確認します。「特別なケースを特別なものにして、確立されたルールを破り始めることはできません。」
データモデルはオブジェクトプロトコルを記述し、特別なメソッドは組み込みオブジェクトによって実装されるプロトコルです。コードスタイルを組み込みタイプまたはより多くのPythonスタイルのコードと同じように動作させるために、代わりに特別なメソッドを使用できます。サブクラス化。
オブジェクトの基本的な要件は、適切な文字列表現が必要であるということです。この要件を満たすために、 __str__
と __repr__
を使用できます。 __repr__
はデバッグに便利で、 __str__
はエンドユーザーに適しています。これが、データモデルに特別なメソッド __repr__
と __str__
がある理由です。
Pythonには多くの特別なメソッドがあります。ここでの主なトピックはデータモデルです。Python言語の設計哲学を理解し、より多くの「Pythonic」コードを作成する方法について考えていただければ幸いです。
Recommended Posts