本記事の要旨
本記事は、Pythonのクラス定義に現れる"def __init__(self):"をとりあえず暗記しておまじないのように書いている方のために、なるべく直感的に納得できるようにするために書きました。
Pythonのクラス定義
Pythonはクラス定義の際に、以下のような形式を取ります。
class demo_class():
def __init__(self):
pass
これが(pythonにしては)直感的ではないということで、自分以外にも初学者の方で苦労されている方は多くいられるかと思います。
参考書(入門Python3)などの説明
__init__()は、クラス定義から個々のオブジェクトを作るときにそれを初期化するメソッドにつけられた特殊名である。
まあ、それだけ言われてもよくわかりません。しかしこの入門Python3は続いてPythonの処理系が何をするかを説明してくれていてそれがわかりやすかったので、それをまとめて、更に図を加えて説明します。
より説明しやすくするため、クラスのメンバ変数nameを追加し、"hoge"を追加する要素をくわえます。
class demo_class():
def __init__(self,name):
self.name = name
a = demo_class("hoge")
print("a: ",a)
print("a.name: ",a.name)
[出力結果]
a: <__main__.demo_class object at 0x1023b6668>
a.name: hoge
Pythonのクラスがどんな動きをするかのイメージ
pythonは関数を実行するように、クラスをインスタンス化することができます。
インスタンスとはオブジェクトの実体であり、インスタンス化は大雑把に言えばメモリ上をプログラムが実行可能な状態にすることを表します。
実際以下の行ではpythonのインタプリタはどこから実行するでしょうか。
a = demo_class("hoge")
- demo_classクラスの定義を参照する
- demo_classクラスの空のオブジェクトを生成する
- 引数をもとに、demo_classクラスのオブジェクトの初期化をする
- メンバ変数nameにstringの"hoge"を代入する
- オブジェクトにaという名をつける
以上のような順番で処理されていきます。
図で表すと以下のような感じ
図の説明
まずはじめに、クラスの定義より、空のクラスオブジェクトを生成します
生成されたクラスオブジェクトは、自らを初期化する(nameメンバに"hoge"を追加)ために、先程のオブジェクトへ手を加えなくてはいけません。このとき、pythonインタプリタからすれば、どのオブジェクトへどんな初期化をすればいいかわかりませんし、変数への参照方法もわかりません。
__init__メソッドは初期化をするための特殊メソッドです。
つまり、Pythonインタプリタにどのオブジェクトをどのように初期化してほしいか明示するために初期化をするための特殊メソッド__init__メソッドに先程生成した空のオブジェクトをself引数として渡すのです。
これにより、自分で作ったオブジェクトを同定することができるようになり、クラスごとに余計な名前を別々に作る必要もなくなるわけです。
ここで問題になるのが、"self.name"です。
def __init__(self,name):
self.name = name
この左辺の"self.name"はメンバ変数を定義しますよということで、オブジェクトにname変数を作成して、引数の"hoge"が入ったnameを代入するということです。
つまり1行目のnameと2行目右辺のnameは表すものが違うわけです。ここが一緒だから初見ではよくわからなくなるのだと思います。
なぜ"self."という前提がつくのかというと、そうすることでインタプリタがどのオブジェクトを参照して処理を行えばいいか明示的になるからです。(たぶん)
(pythonでは"."のあとに続くものをすべて属性と呼びます。)
注意
本稿では、"〇〇するために"や、"〇〇するためである"というように断定し、限定的な目的のための手段として説明する部分が多々ありますが、これはイメージを掴むことを第一目標にするために取った手法であり、長い学習スパンで鑑みるといささか問題があります。
参考
入門Python3
公式ドキュメント