27
23

More than 1 year has passed since last update.

【Python】selfを分かりやすく説明する

Last updated at Posted at 2022-02-20

selfとは?そして、インスタンス変数とは?

sample.py
def __init__(self, word):
    self.word = word

selfは、インスタンス自身を指します

sample.py
self.word = word # self.インスタンス変数 = 値

そして、上記のコードではインスタンス自身(self)のwordという変数へ、引数として与えられたwordという変数を代入しています。

インスタンス変数について

インスタンス変数の特徴としては、

特徴
1 生成されたインスタンスごとに別の値を持つ変数
2 クラス内の全メソッドで使用できる
3 クラスの外からインスタンス変数へアクセスしたい場合、インスタンスを作成しなければならない

以上のものがあります。詳しく記載します。

以下のコードは、Dogクラスから、犬種のインスタンスを作成してます

sample.py
class Dog:
    def __init__(self, name):
        self.name = name # self.インスタンス変数 = 引数のname(ここでは"チワワ")

    def bark(self):
        return "吠えたのは、" + self.name # self.name:インスタンス変数へアクセス

chihuahua = Dog("チワワ")
print(chihuahua.name)
# > チワワ
print(chihuahua.bark())
# > 吠えたのは、チワワ

1. 生成されたインスタンスごとに別の値を持つ変数

sample.py
chihuahua = Dog("チワワ")
print(chihuahua.name)
# > チワワ
dachshund = Dog("ダックスフンド")
print(dachshund.name)
# > ダックスフンド

引数によって、インスタンスがダックスフンドになったりします。

2. クラス内の全メソッドで使用できる

sample.py
def bark(self):
    return "吠えたのは、" + self.name
def bite(self):
    return "噛み付いたのは、" + self.name

例ではbarkメソッドしか記載がないですが、bite(噛み付く)メソッドとかを作ってもそこでself.nameが使用できます

3. クラスの外からインスタンス変数へアクセスしたい場合、インスタンスを作成しなければならない

sample.py
chihuahua = Dog("チワワ")
chihuahua.name
# インスタンス名.インスタンス変数

インスタンスを生成してアクセスしています。

そもそもな何故に、まどろっこしいselfを書くのか?

以下の記事でわかりやすく書かれているので、理解することが出来ます

簡単にまとめてみます。

selfを書く意味

結論から言うと、
オブジェクトからメソッドへアクセスした時に、引数であるオブジェクトが省略されているため、selfを記載しています

どういうことかというと、
実は、組み込み関数にヒントがあります。

組み込み関数

プログラミング言語ごとにあらかじめ用意されている関数の事です。
例えば、最初の文字列を大文字で返すcapitalize()であれば

sample.py
print(str.capitalize("python"))
# > Python

引数に"python"というオブジェクトをとっています

続いてこちら、

sample.py
language = "python"
print(language.capitalize())
# > Python

なんと、引数を取っていないにも関わらず期待通りの出力がされています。

なぜか?

実は、暗黙的にlanguage.capitalize(language)が実行されています

こちらがcapitalize()が定義された場所

buittins.pyi
class str(Sequence[str], _str_base):
    # 省略
        def capitalize(self) -> str: ...

引数には、selfをとっています。

そして、
language.capitalize(language)が見ずらいということで、引数となるオブジェクトを省略したlanguage.capitalize()でOKってことになっています

selfを書かなかった場合について考えてみる

正:コンストラクタ

sample.py
class SampleClass():
    def __init__(self, word):
        self.word = word

sample = SampleClass("Hello World")
print(sample.word)

# > Hello World

__init__というコンストラクタが最初に実行されます
クラスの外で、sampleというインスタンスを作成して、インスタンス変数wordへアクセスしています

Hello Worldが正しく出力されています

誤:selfを抜いてみる

sample.py
class SampleClass():
    def __init__(word):
        word = word

sample = SampleClass("Hello World")
print(sample.word)

# > TypeError: __init__() takes 1 positional argument but 2 were given

selfをそのまま取り外したコードになります
すると案の定エラーですね。
TypeError: __init__() takes 1 positional argument but 2 were given

以下の例でも確認してみましょう

正:クラスメソッド

sample.py
class SampleClass():
    def call(language):
        print(language)

SampleClass.call("python")

# > python

こちらのコードはSampleClassというクラスから、クラスメソッドにアクセスしています
直接だと、selfがなくても問題なく出力できました

一方で、、、

誤:インスタンスを作成してアクセス

sample.py
class SampleClass():
    def call(language):
        print(language)

language = SampleClass() # インスタンス作成
language.call("python")

# > TypeError: call() takes 1 positional argument but 2 were given

インスタンスを作成して、そこからSampleClass()クラス内のメソッドを呼び出してみると、

TypeError: call() takes 1 positional argument but 2 were given
引数は1つ欲しいのに、2つ与えられているとエラーが

これがつまり、インスタンスからアクセスしたため、
隠れたselfが与えられているということですね

参考

27
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
23