本日はpython classのself引数のお作法について
class enemy():
def __init__(self):
self.hp = 100
# self.attack = 50
self.defense = 10
def attack():
print("attack")
en1 = enemy()
en1.attack()
上記のコードはエラーとなる。
エラーコードは
Cell **In[21], line 10
** 7 print("attack")
** **9 en1 = enemy()
**---> **10 en1.attack()TypeError: attack() takes 0 positional arguments but 1 was given
となります。
GPT曰く、
このエラーメッセージは、attack
メソッドが引数を受け取らないように定義されているにもかかわらず、呼び出し時に1つの位置引数が渡されたことを示しています。
Pythonのメソッドでは、メソッドがインスタンスに属している場合、そのインスタンス自体が最初の引数としてメソッドに自動的に渡されます。この引数は通常self
と名付けられます。
とのこと。
簡潔にいうと、classからインスタンスを生成し、メソッドを呼び出すと、インスタンス自体をメソッドの引数に自動的に渡すのがお作法らしい。
要はpythonの言語仕様としてそうなっているらしい。
他に理解のための例として、コメントアウトを除いたもののエラーを見ると、インスタンス自体を渡すことを前提としていることを感じられるエラーが出てくる。
class enemy():
def __init__(self):
self.hp = 100
self.attack = 50
self.defense = 10
def attack():
print("attack")
en1 = enemy()
en1.attack()
TypeError Traceback (most recent call last)
Cell In[22], line 10
7 print("attack")
9 en1 = enemy()
---> 10 en1.attack()
TypeError: 'int' object is not callable
このエラーメッセージは、int
(整数)オブジェクトが呼び出し可能(関数のように)として扱われた場合に発生します。この場合、enemy
クラスにはattack
という名前の属性とメソッドがあります。self.attack = 50
という行で、attack
を整数値50を持つ属性として定義しています。その後、en1.attack()
の行で、attack
メソッドを呼び出そうとしていますが、この時点で attack
は整数値50を持つ属性として既に定義されているため、メソッドとして呼び出すことができず、エラーが発生します。
初めのコードに戻ると。
enemy
クラスのattack
メソッドが引数を受け取らないように定義されていますが、インスタンスメソッドとして呼び出されると、Pythonは自動的にそのインスタンス(この場合はen1
)を引数としてattack
メソッドに渡します。しかし、attack
メソッドがこの自動的に渡される引数を受け取るように定義されていないため、エラーが発生します。
この問題を解決するには、attack
メソッドの定義にself
引数を追加する必要があります。これにより、メソッドはインスタンス自体を引数として受け取ることができ、エラーが解消されます。
とのことで、メソッドを呼び出すとき、.の左側にあるインスタンスを引数として呼び出すらしい。
別にプロパティ関係ないし動くんじゃねとコードリーディングの時は思ったが、このようなインスタンス自体を参照している過程を前提に言語が設計されているからエラーになると。。。
self
ってそういう意味だったのね。