# __init__ ってなに?

__init__ は、かなり難しくて、つまずきどころかなと思います。 なぜ難しいかというと2つの理由があります。

1つ目は、難しい概念が色々と隠れているからです。 2つ目は、自動的に色々とやってくれているからです。

そのため理解する必要はなく、 まず __init__ の動作を   覚えてしまうこと   が大事かなと感じたりもします。

伝わるかは厳しいのですが __init__ を見ていきます。

# Step 1. オブジェクトってなに?



「値」と「処理」をまとめたものです。


ここに猫 tora がいたとします。





tora は2つの「値」を持っています。 猫 tora は、名前 name があり、とら と言います。 猫 tora は、動物として分類 family されていて、 科に属します。

>>> tora.name
'とら'
>>> tora.family
'猫'
>>> 

tora は2つの「処理」を行うことができます。 猫 tora は、鳴く say することができます、にゃー と。 猫 tora は、唸る growl することができます、ウー と。

>>> tora.say()
にゃー
>>> tora.growl()
ウー
>>> 

# Step 2. クラスってなに?



共通 の「値」と「処理」をまとめたものです。


tora は、動物として分類 family されています。 みな鳴くこと say ができますし、唸ることもできます growl。 もし Step 1 で書かれた猫を Python で書けば次のようになります。

#
# 対話モード >>> に
# コピペで動きます。
#
class Cat:
    family = '猫'
    
    def say(self):
        print('にゃー')
    
    def growl(self):
        print('ウー')

tora = Cat()
tora.family
tora.say()
tora.growl()
>>> tora.family
'猫'
>>> tora.say()
にゃー
>>> tora.growl()
ウー
>>> 

# Step 3. インスタンス化ってなに?



クラスからオブジェクトを作ること


書式は以下の通りです。

オブジェクト = クラス名()
>>> tora = Cat()  # <--- ここがインスタンス化
>>> tora.family
'猫'
>>> tora.say()
にゃー
>>> tora.growl()
ウー
>>> 

インスタンス化したばかりのオブジェクトの名前 name を使おうとするとエラーになります。

#
# 対話モード >>> に
# コピペで動きます。
#
class Cat:
    family = '猫'
    
    def say(self):
        print('にゃー')
    
    def growl(self):
        print('ウー')

tora = Cat()
tora.family
tora.say()
tora.growl()

tora.name  # <--- エラーになります。
>>> tora.name  # <--- エラーになります。
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Cat' object has no attribute 'name'
>>> 

なんでエラーになったのでしょうか? それはまだ名前 name をつけてあげていないからです。

吾輩わがはいは猫である。名前はまだ無い。
夏目漱石 - 吾輩は猫である

名前 name は猫ごとに違います。 生まれたての猫には、まだ名前 name がないという訳です。

エラーにならないように名前をつけてあげたいと思います。

#
# 対話モード >>> に
# コピペで動きます。
#
class Cat:
    family = '猫'
    
    def say(self):
        print('にゃー')
    
    def growl(self):
        print('ウー')

tora = Cat()
tora.family
tora.say()
tora.growl()
tora.name = 'とら'  # <--- 1行追加しました。
tora.name
>>> tora.name
'とら'
>>> 

エラーが消えました。





# Step 4. __init__ ってなに?



インスタンス化する時の処理を書く関数


インスタンス化する時に実行する処理を追加する オブジェクトをインスタンス化する時に、ちょっと改造したいことがあります。

例えば、猫クラス Cat をインスタンス化してから名前をつけるのは面倒です。

tora = Cat()        # インスタンス化してから 
tora.name = 'とら'  # 名前をつける

こうやって1行で書けたら、良さそうです。

tora = Cat()

インスタンス化する時に名前をつけたいです。 インスタンス化する時に __init__ が、自動的に呼び出されるのでこれを使います。

#
# コピペで動きます。
#
class Cat:
    family = '猫'
    
    def say(self):
        print('にゃー')
    
    def growl(self):
        print('ウー')

    def __init__(self):
        # 1. 第一引数 self には名前のない猫オブジェクトが
        #    自動的に代入されています。
        self.name = 'とら'
        
        # 2. self は return しない        
        # return self

tora = Cat()
tora.name
>>> tora.name
とら
>>> 

# (補足)return はいらない。

関数とは違い  return 文を使わなくても  自動的に self が返されます。

# (補足)頭に self をつける。

 頭に self をつけていない変数は、あとから参照できません。  自分は Python を習いたての頃、self をつけ忘れているのに気づけなくて普通に数日溶かしました笑

#
# コピペで動きます(エラーで弾かれます)。
#
class Cat:
    def __init__(self): 
        name = 'とら'

tora = Cat()
tora.name
>>> tora.name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Cat' object has no attribute 'name'
>>> 




# Step 5. self ってなに?

self という文字をたくさん見るのですが、self には「生まれたての猫」が入っています。

#
# コピペで動きます。
#
class Cat:
    def __init__(生まれたての猫):
        生まれたての猫.name = 'とら'

tora = Cat()
tora.name
>>> tora = Cat()
>>> tora.name
'たま'
>>>

self じゃなくてもいいんです。cat でも動きます。

#
# コピペで動きます。
#
class Cat:
    def __init__(cat):
        cat.name = 'とら'

tora = Cat()
tora.name
>>> tora.name
'とら'
>>>

ここで大事なことは self と書かなくても動くと言うことです。 じゃあなんでみんな self って書いているのでしょうか?

それは偉い人たちがみんなでそうやって書こうね、と決めたからです。 PEP 8 という文章で定められています。PEP 8 は、知らなくても大丈夫です。

# Step 6. __init__ を書き換える

すべての猫の名前が「たま」なのかな?と疑問に思われた方、それは非常に正しい判断です。 ちゃんと名前を変えてあげられるようにしたいと思います。

ここで大事なのは __init__(self, name) メソッドと、 Cat("ドラえもん")  引数の数が違うこと  です。

#
# コピペで動きます。
#
class Cat:
    family = '猫'
    
    def say(self):
        print('にゃー')
    
    def growl(self):
        print('ウー')
    
    def __init__(self, name):  # <--- __init__ の引数は2つ
        self.name = name

tama = Cat('たま')             # <--- インスタンス化の引数は1つ
tama.name
dora = Cat('ドラえもん')
dora.name
>>> tama = Cat('たま')
>>> tama.name
'たま'
>>> dora = Cat('ドラえもん')
>>> dora.name
'ドラえもん'
>>> 

# (補足)インスタンス変数とローカル変数

さきほどの"(補足)頭に self をつける" の繰り返しになります。

self をつけて後からから確認することができる変数を  インスタンス変数  と言います。

self をつけず後から確認することができない変数を  ローカル変数  と言います。

#
# コピペで動きます。
#
class Cat:
    def __init__(self, name):
        # インスタンス変数
        #   そこで名前をつけてあげる。
        #   その時、必ず self をつけないといけません。
        self.name = name
        
        # ローカル変数
        #   self をつけない変数は参照できません。
        age = 0

dora = Cat('ドラえもん')
dora.name
dora.age  # <--- AttributeError になります
>>> dora = Cat()
>>> dora.name
'ドラえもん'
>>> dora.age
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  AttributeError: 'Cat' object has no attribute 'age'
>>> 

# (補足)

あとはこの辺も結構混乱しがちかな...と。 こちらの方のツイートを引用させていただきます。 下の方にある「左右どちらも同じ」と書かれた図を見てください。






__init__は難しい

__init__ の説明は以上になります。 __init__ 自体結構難しいと思います。 理由は大きく分けて2つあります。

# 理由1 難しい概念がしれっと入っているから

まず第一に、「名前空間」、「スコープ」といった難しい概念がしれっと入っているからです。

「インスタンス変数」と「ローカル変数」は、違うものです。 「インスタンス変数」と「ローカル変数」は、 「スコープ」、「名前空間」という、とても深い内容と密接に関わっていたりします。

「スコープ」?そんなの知ってるよ!って感じですし、 「名前空間」も「苗字と名前」くらいの簡単な概念なのですが。

ただ、言葉では理解できていても、使えるかどうかとなると、なかなか四苦八苦する感じになるかなと。 自分は四苦八苦しました笑

回数こなしていけば、動作を覚えてしまうと思います。 無理して、すぐに理解する必要はないかなとも思ったりもします。

なぜなら、掘り下げて理解しようとすると、やる気が続かないこともあるからです。 とりあえず、これはこういうものということで、先に進めたほうが、楽しいかなと思ったりもします。

とはいえ、掘り下げて1つずつ積み重ねたほうが理解が速い場合があるので、 それも人によりけりかなとも思いはするのですが...

# 理由2 自動でいろんなことをしてくれるから

また第二に、いろんなことを自動的にしてくれているからです。

  1. 関数とは違い自動的に、self にインスタンスが代入される
  2. 関数とは違い自動的に、インスタンス化した時に呼び出される
  3. 関数とは違い自動的に、return していないのに self が返される

でも上の説明では、それを全て割愛しています... 自動的にやってくれるというのは、便利にはなるのですが、 見ていこうとすると説明が煩雑になり、逆に理解することが結構難しくなったりします。

下記の文章は、PEP 20 という Python のすごい人が書いた Python のコツみたいな文書からの引用です。 下手に自動化させるよりも面倒でもベタ書きしてもらった方がわかりやすいコードになるよ。 という意味だと個人的に思っています。

明示的であることは、暗黙的であるより良い。
Explicit is better than implicit.
PEP 20 - The Zen of Python

# self ってなに?

__init__, self, suer() は Python の鬼門です。 self は、生まれたての猫でもありますし、関数の第一引数でもあります。

class User:
    def __init__(self, name):
        #        ^^^^ なにこれ?
        self.name = name

user = User('サーバルちゃん')
Last Updated: 11/11/2019, 11:17:29 PM
x 消す
銀河英雄伝説が無料!