アドバンスドPython。 マジックメソッドとは何ですか?

この記事では、すべてのPythonプログラマが知っておくべきPythonの特殊メソッドを紹介します

Farhad Malik

Follow

May 16, 2020 – 14 min read

マジックメソッドは私たちのアプリケーションを豊かにするのに一役買ってくれます。 それらは間接的に Python コードにマジックを追加します。 これは Python 開発者向けの上級レベルのトピックであり、Python プログラミング言語を使用している/使用しようとしているすべての人にお勧めします。

The magic methods gives us more control over how our application behaves.

この記事の目的は、マジックメソッドが何か、Python アプリケーションの構築にどう使用できるかを説明することです。

主要なマジック メソッドを概説する目的は、アプリケーションを豊かにするためにカスタム クラスでこれらのメソッドをオーバーライドしたいかどうかを理解するためです。

Magic methods は Python プログラミング言語を非常に強力にします

フォト バイ Rodion Kutsaev オン Unsplash

What Are The Python Magic Methods?

Pythonのマジックメソッドは、特殊メソッドやダンダーメソッドとも呼ばれます。 これらはダブル アンダースコアで囲まれます (例: __init__())。

オブジェクトはいくつものマジック メソッドを持つことができます。 オブジェクトは Python のデータの抽象化です。

マジックメソッドは新しいオブジェクトを構築して初期化するために使用され、辞書としてオブジェクトを取得するのに役立ち、他の操作と一緒にオブジェクトを削除するために使用されます。 Python のすべてのメソッドは public ですが、コーディング規約ではすべての private メソッドをダブルアンダースコア __<method>__()

で囲むようになっています。 また、メソッドはマジック メソッドを持つクラスによって内部的に呼び出されることを意図しているので、オブジェクトの呼び出し元はメソッドを直接呼び出してはいけないことを意味します。

私たちはマジック メソッドをオーバーライドして、独自のカスタム機能を提供することができます。

Photo by Cristian Escobar on Unsplash

カスタムクラスを作成し、マジックメソッドの概念を説明し、整数、文字列、リスト、辞書で重要なマジックメソッドを概観する予定である。

記事が進むにつれて、マジック メソッドが存在する理由とその使用方法について、より明確なイメージを構築し始めることでしょう。

もしあなたが Python プログラミング言語を初心者から上級者まで理解したいのであれば、以下の記事を強くお勧めします。

カスタム クラスを作成することからマジック メソッドの話題を始め、その後、マジック メソッドの使用方法を説明します。

The Usecase To Understanding Magic Methods

以下のスニペットで、私は Human というクラスを作成し、そのクラスでインスタンスを作成しました。

このコードのスニペットは、マジック メソッドの理解に役立ちます。

Note, object human の id は整数型、name 属性は string 型、properties は list 型、properties maps は dictionary 型です。

読みやすいように、マジック メソッドを各種データ型セクションにグループ化しました。 しかし、同じマジック メソッドが異なるデータ型にあります。

マジック メソッドをオーバーライドして機能を強化し、ビジネス ニーズに最適なカスタム ロジックを作成できます。

Class:

人間オブジェクトに関連付けられたマジック メソッドを理解しましょう。 dir(human) メソッドを実行すると、human オブジェクトのすべての関数と属性名がリストアップされます。

human オブジェクトに関連付けられているメソッド/属性は合計 29個あります。 そのうち、26個がマジックメソッドです。

かなり多くの特殊メソッドがあることになりますね。 これらのメソッドはHumanクラスのベースタイプから継承されます。

次のセクションでは、主要なマジック メソッドについて説明します。

__delattr__

このメソッドは、クラスから属性を削除しようとするときに呼び出されます。

Human クラスでこのメソッドを実装することにより、機能をオーバーライドできます。

def __delattr__(self, item):
print('Deleting attribute ' + item)
return object.__delattr__(self, item)

これで、属性を削除しようとすると、メッセージが表示されます。 Deleting attribute

また、属性に値を割り当てる __setattr__() と属性から値を取得する __getattr__() というメソッドもあります。

_delattr__()の使用例としては、オブジェクトの特定の属性を削除できないようにしたり、特定の属性が削除されたときに特定のアクションを実行したい場合があります。

__dict__

このメソッドは、オブジェクトを表す辞書を返します。 辞書のキーはオブジェクトの属性で、値は属性の値です。

インスタンスとして:

human = Human(2, 'Malik').__dict__
print(human)

上記のコードは以下を返します:

{‘id’: 2, ‘name’: ‘Malik’, ‘addresses’: , ‘maps’: {}}

__dir__

クラスで __dir__() メソッドをオーバーライドすることで、dir() メソッドを上書きすることができます。 インスタンスとして、dir() メソッドによって返される結果から内部メソッドを削除できます:

__eq__

このメソッドは == 操作を実行しようとしたときに呼び出されます。 名前が異なっていても id 属性が同じであれば、2 つの人間オブジェクトは等しいと考えます。

この機能を実現するために __eq__() メソッドをオーバーライドできます。

__ge__

例として、2 つの Human オブジェクトがあるとします:

first = Human(1, 'Farhad')
second = Human(2, 'Malik')

また、私たちのプロジェクトには、大きな Id を持つ Human オブジェクトは他の Human オブジェクトよりも大きいとみなすという規則があるとしましょう。 したがって、__gt__() メソッドをオーバーライドしてカスタム ロジックを実装できます:

def __ge__(self, other):
return self.id >= other.id

これで、2 番目の人間オブジェクトの ID は最初の人間オブジェクトより大きいので、False を返します:

print(first >= second)
Returns False

オペレーター ≤ が実行されるときに実行する __lt__() メソッドも存在します。

__hash__

ハッシュは、オブジェクトを整数に変換するために使用されます。

優れたハッシュアルゴリズムは、ハッシュの衝突の数が少なくなるように、辞書/セットにアイテムを設定しようとするときにハッシュが実行される。 hash__() メソッドをオーバーライドすることにより、独自のハッシュ アルゴリズムを提供することができます。 __hash__() アルゴリズムをオーバーライドして self.id をハッシュ整数として返すことができます:

def __hash__(self):
return self.id

2つのオブジェクトを作成して、セットコレクションに保存できます。

first = Human(1, 'Farhad')
second = Human(2, 'Malik')
my_set = set()
print(len(my_set))
#returns 2

ここで、両方のオブジェクトの id を 1 に設定し、この演習を繰り返すと、セットには 1 つの要素しか表示されません。これは、両方のオブジェクトの name 属性が異なっていても id 属性が同じで、同じハッシュ キーを持っているためです。

first = Human(1, 'Farhad')
second = Human(1, 'Malik')
my_set = set()
print(len(my_set))
#returns 1

__init__

_init__()メソッドは、コンストラクタを呼び出してクラスの新しいインスタンスを作成するときに実行されます。

インスタンスとして、

human = Human(1, 'farhad')

実行しようとしたとき、__init__() メソッドが実行されました。

この機能をオーバーライドして、独自の引数と動作をこの中に渡すことも可能です。

インスタンスとして、Humanクラスの__init__()メソッドがあります。

def __init__(self, id, name, addresses=, maps={}):
self.id = id
self.name = name
self.addresses = addresses
self.maps = maps

Photo by Cederic X on Unsplash

__init_subclass__

これはメタクラスの使用事例の 1 つです。 クラスがサブクラス化され、そのオブジェクトが作成されると、__init_subclass__() メソッドが呼び出されます。

基本的に、このメソッドは、サブクラス化されたことを親に通知します。 このフックは、与えられたクラスのすべてのサブクラスを初期化することができます。 したがって、このメソッドはサブクラスを登録し、サブクラス上の属性にデフォルト値を割り当てるために使用される。

メタクラスがどのように動作するかについては、次回の記事で説明します。

__new__

クラスの新しいインスタンスを作成したい場合、__new__(cls)メソッドが実行されます。

例として、Human() コンストラクタが呼ばれるたびに ‘Human creating…’ と表示したい場合を考えてみましょう。

以下のように __new__(cls) メソッドの機能をオーバーライドします:

def __new__(cls, *args, **kwargs):
print('Human creating...')
return object.__new__(cls)

その結果、インスタンスを作成しようとしたときに Human creating… が出力されます:

human = Human(1, 'Farhad', , {'London':2, 'UK':3})

__sizeof__

このメソッドは sys.getsizeof() を実行すると、呼び出されます。 これは、メモリ上のオブジェクトのサイズをバイト単位で返します。

__str__

これは、id=1. name=Farhad.

__str__() 関数は、オブジェクトのユーザーフレンドリーな表現を返すように試みるべきです。

__weakref__

この __weakref__ オブジェクトはターゲットオブジェクトへの弱い参照のリストを返します。 本質的には、ガベージコレクションが弱い参照に参照が収集されたことを知らせるのに役立つ。 したがって、オブジェクトが基礎となるポインタにアクセスすることを防ぎます。

写真: Yousef Espanioly on Unsplash

Integer

これで記事の次のセクションへ進みましょう。 オブジェクトhumanのidプロパティはint型であることがわかります。

print(len(list(filter(lambda x: x.startswith('__') and x.endswith('__'), dir(human1.id)))))

ここで主要なメソッドを説明します。

__add__

このメソッドは、2 つの数字を足そうとするときに呼び出されます。

例として、

human.id + 2 は human.id.__add__(2)

__and__

このメソッドは &演算子を使用しようとするとき実行されます。g.:

return self & another_value

__bool__

このメソッドはオブジェクトに対してブーリアン・チェックを行おうとしたときに実行されます。例:

self != 123

__floordiv__

このメソッドは //演算子を実行したときに実行されます。

フォト by Johannes Plenio on Unsplash

__getnewargs__

時折、Pythonではオブジェクトを漬けることがあります。 pickling はメモリ上にオブジェクトのバイトストリーム表現を作成し、必要に応じてディスクに保存できます。

__getnewargs__() メソッドは、ターゲットオブジェクトを再作成するために pickling オブジェクトをロードバックする必要があるかについて pickling プロセスに情報を提供します。 特に、どのようにオブジェクトはnew()メソッドに引数を渡すことによって作成される必要があります。 したがって、「get new args」という名前になっています。

__index__

その結果、__index__()メソッドを実行すれば、オブジェクトを整数に変換することができるようになりました。 このメソッドをオーバーライドして、インデックスがどのように生成される必要があるのか、独自の機能を提供することもできます。

インスタンスとして:

first = Human(1, 'Farhad')
print(~first.id)

実行するのと同じです:

first = Human(1, 'Farhad')
print(first.id.__invert__())

__lshift__

このメソッドは例えば self << 値の左シフトを与えます。

注意: __rshift__() は >> 演算子を実行するときに実行されます。

__mod__

このメソッドは%演算子を使用するときに呼び出されます。

__neg__

このメソッドは、負の – 演算子を使用するときに実行されます。例:

first.id — second.id

__subclasshook__

このメソッドをオーバーライドすると issubclass() メソッドのカスタマイズを行うことができます。 基本的に、クラスがサブクラスである場合は True を、そうでない場合は False を返します。 また、このメソッドは、既存のアルゴリズムを使用できる NotImplemented を返します。

このメソッドは、issubclass() メソッドの結果をカスタマイズすることができます。

Photo by Patrick Selin on Unsplash

String

この記事の次のセクションに進みましょう。

オブジェクトhumanのnameプロパティはstring型であることがわかります。 次に、このプロパティに対して dir(human.name) を実行し、ダブル アンダースコアで囲まれたメソッドを除外すると、合計 33 個のマジック メソッドがあることがわかります。

__contains__

このメソッドは、指定した文字が存在するかどうかを確認するときに実行されます。

__len__

このメソッドは、文字列の長さを返します。

文字列の長さを計算するために特定の文字だけをカウントしたい場合は、__()__メソッドをオーバーライドしてその機能を提供することができる。

__repr__

このメソッドは、オブジェクトの開発者向けの表現を作成するときに実行されます。

注意: __repr__ は、クラス内に __str__() の実装がない場合、print(object) のときに実行されます。 name=Farhad (<class ‘str’>)

_repr__()メソッドは、オブジェクトの公式表現を生成することを意図する必要があります。

__iadd__

時には、割り当て e と一緒に加算演算子を使用することがあります。g.

self.id += 1

これは self.id = self.id + 1

代入で加算を実行するときに iadd() メソッドが実行されます。

さらに、**= が実行されるときに __ipow__() メソッドが実行されます。

マジックメソッドの__iand__()は代入でビット単位のANDを実行するためのもので、__ior__()は次のように!=を実行しようとしたときに呼び出されます:i != j

List

ここで次のセクションに進みましょう。 オブジェクトhumanのaddressプロパティはlist型である。

print(len(list(filter(lambda x: x.startswith('__') and x.endswith('__'), dir(human1.addresses)))))

ここで主要なメソッドを説明します。

__reduce__

オブジェクトがpickleされるとき、__reduce__()メソッドが実行されてpickleがそれを構築する方法を理解できるようにオブジェクトが返されるようにします。

__reduce_ex__

__reduce_() メソッドは、 __reduce__() メソッドより pickle によって優先されます。 これは、pickle の後方互換性を提供し、オブジェクトに pickled バイトストリームを構築するために使用されます。

__reversed__

__reversed__() メソッドは、逆順にコレクションを逆転しようとするときに実行されます。

reversed(collection) または collection.reverse() が呼ばれたとき、実行されます。

reversed__() メソッドをオーバーライドすることにより、希望する結果を得ることができます。

Dictionary

この記事の第5章に進みます。

Dictionary は Python の主要組み込み型の 1 つです。 dir(human.maps) を実行し、ダブルアンダースコアで囲まれたメソッドを除外すると、全部で 29 個のマジックメソッドがあることがわかります。g.

del dictionary

__getitem__

このメソッドは、キーに対応するアイテムを取得しようとしたときに実行されます。

item = dictionary

__setitem__

このメソッドは、辞書に項目を設定しようとしたときに実行されます:

dictionary = item

__iter__

このメソッドは、コレクションのイテレータを返します。

iter__() メソッドをオーバーライドすることにより、iterator() がどのように実行されるかを上書きできます。

最後に __call__() についてのメモ

もし私たちのオブジェクトを呼び出し可能にしたかったらどうでしょうか。 human オブジェクトを呼び出し可能な human() 関数にしたいと考えたとしましょうか。

__call__()メソッドはクラスを関数として扱うことができます。

human = Human(1, 'Farhad')
human()

私たちの Human クラスで __call__() マジックメソッド実装を提供すると、この機能を達成できます。

これは、次のように表示します:

You tried to call
Arguments: ()
Keyword Arguments: {name=Farhad (<class ‘str’>)
Call completed

_call__()メソッドをオーバーライドすることにより、オブジェクトを関数として返すデコレーターを実装したり、実際のオブジェクトを渡して関数を引数として受け入れるライブラリさえ呼び出すことができるようになった。

Photo by Dollar Gill on Unsplash

Summary

このテーマは Python 開発者にとって上級レベルですが、Python プログラム言語を使用している/使用しようとしているすべての人に推奨するものです。

この記事は、マジックメソッドとは何か、そして、それらがどのように Python アプリケーションを構築するために使用できるかを説明することを意図しています。 Python のすべてのメソッドは public ですが、コーディング規約では、すべての private メソッドをダブル アンダースコア __<method>__()

で囲むことになっています。 また、オブジェクトの呼び出し元が直接メソッドを呼び出してはならず、マジックメソッドを持つクラスが内部でメソッドを呼び出すという意味もあります。

マジック メソッドをオーバーライドして機能を充実させ、ビジネス ニーズに最も適したカスタム ロジックを作成することが可能です。

コメントを残す

メールアドレスが公開されることはありません。