クラス内で定義されている関数(メソッド)に、引数に「self」があるものと無いものがあるので違いを調べてみた。
#メソッドの第一引数にある「self」ってそもそも何?
「self」自体は引数の名前に過ぎず、他の名称でもいい。
Pythonではメソッドの第一引数は「self」が必須であり、自身のクラスのインスタンスを受け取るとコーディング規約で決まっているらしい。
他の言語から来た人には不評な一方、このおかげでだいぶ便利になっているらしい。
参考:https://coreblog.org/ats/translation-of-why-explicit-self-has-to-stay/
Pythonのメソッド引数に書く「self」はしばしば,他言語からのPython移民を中心に「ウザイ」「キモイ」「消えてなくなれ」と攻撃の対象となることが多いのです。
#「self」のあり・なしの違いは?
メソッドの第一引数に「self」が必須なのに、引数なしのメソッドがあるのは何故なのか?
結論から言うと「self」があるのは普通のメソッド、無いのはスタティックメソッド。
さらに第一引数に「cls」が必要なクラスメソッドというのもあるらしいが今回は省略。
参考:http://nihaoshijie.hatenadiary.jp/entry/2018/06/08/200823
メソッドの種類 | 第一引数 | 宣言 | 呼び出し元 | インスタンスオブジェクト | クラスオブジェクト |
---|---|---|---|---|---|
普通のメソッド | self | なし | インスタンスのみ | 操作できる | 操作できる |
クラスメソッド | cls | @classmethod | インスタンス・クラス | 操作できない | 操作できる |
スタティックメソッド | 不要 | @staticmethod | インスタンス・クラス | 操作できない | 操作できない |
#そもそも「クラス」と「インスタンス」ってなんだっけ?
クラスは設計書で、インスタンスは設計書をもとに作られた実体。
例:クラス→車の設計書 インスタンス→設計書を元に実際に製造された車
#普通のメソッドとスタティックメソッドってどう使い分けるべき?
- 普通のメソッド
→現在のガソリンの残量を取得するメソッド。ガソリンの残量は製造された車(インスタンス)ごとに残量が違うから - スタティックメソッド
→タイヤの数を取得するメソッド。タイヤの数は設計書(クラス)で決められており、製造された車(インスタンス)に依存しないから。
つまり
タイヤの数を知りたいだけならわざわざ実際に車を製造しなくていいよね?
→普通のメソッドだと第一引数「self」に製造した車を渡さなきゃいけない
→スタティックメソッド使おう!
ってことらしい。
※追記:よく考えてみたらこれも正確じゃない。タイヤの数をクラス変数として持たせている場合は、スタティックメソッドだとアクセスできないのでクラスメソッドを使う。
タイヤの数を固定値で返す場合はスタティックメソッドでOKだけど、それだとクラスの意味がない。
クラスもインスタンスも参照しないメソッドならクラスに入れる必要がない。
つまりスタティックメソッドはいらない子・・・?。
#スタティックメソッドで「@staticmethod」を宣言しないとどうなるの?
クラスから呼び出したときは問題なし。
インスタンスから呼び出したときに普通のメソッドだと解釈され、第一引数が自クラスのインスタンスじゃないのでエラーになる。
以下、検証結果。
# スタティックメソッドの検証。
# クラスの定義
class test:
# 宣言あり、引数なしのスタティックメソッド。→インスタンスから呼び出しても動く。
@staticmethod
def myfunc1():
print("func1")
# 宣言無し、引数なしのスタティックメソッド。→インスタンスから呼び出すとエラー。
def myfunc2():
print("func2")
# 宣言あり、引数ありのスタティックメソッド。→インスタンスから呼び出しても動く。
@staticmethod
def myfunc3(msg):
print(msg)
# 宣言無し、引数ありのスタティックメソッド。→インスタンスから呼び出すとエラー。
def myfunc4(msg):
print(msg)
# インスタンスの作成
t = test()
# 宣言あり、引数なしのスタティックメソッド。→インスタンスから呼び出しても動く。
test.myfunc1() # クラスからの呼び出し→func1
t.myfunc1() # インスタンスからの呼び出し→func1
# 宣言無し、引数なしのスタティックメソッド。インスタンスから呼び出すとエラー。
test.myfunc2() # クラスからの呼び出し→func2
t.myfunc2() # インスタンスからの呼び出し→エラー
# 宣言あり、引数ありのスタティックメソッド。インスタンスから呼び出しても動く。
test.myfunc3("func3") # クラスからの呼び出し→func3
t.myfunc3("func3") # インスタンスからの呼び出し→func3
# 宣言無し、引数ありのスタティックメソッド。インスタンスから呼び出すとエラー。
test.myfunc4("func4") # クラスからの呼び出し→func4
t.myfunc4("func4") # インスタンスからの呼び出し→エラー