回答
単刀直入に言えば、__インスタンス化していない__のが原因です。
解説
例えば、こんな感じでutilっぽく複数の関数を一つのクラスにぶら下げる形でまとめているとします。
(ここで違和感を感じたあなたはもうこの記事を読む必要はないですね笑)
class SomeClass:
def say_hi():
print('hi')
def output_arg(var1):
print(var1)
さて、ここで下記のコードを実行したらどんな出力になるでしょうか。
SomeClass.say_hi()
答えは「 hi 」ですね。
ただ、このコードにかっこを加えたこのコードを実行したらどうなるでしょうか?
SomeClass().say_hi()
答えは__エラー__となります。
この()がつくことによる違いの理由は__インスタンス化しているかどうか__にあります。
一番上のコードをお見せした時に感じてほしい違和感の正体にもつながってきますが、
クラスは本来__インスタンス化されてから処理が行われる__のが一般的です。
よく見るのだとこんな感じですよね。
class Human:
def __init__(self, name):
self.name = name
def greet(self):
print('Hi, I am ' + self.name)
Mike = Human('Mike')
Mike.greet()
>>> Hi, I am Mike
このコードのポイントとしては、__Mike__という変数に__Human__というクラスをインスタンス化してあてがった形となっている点が挙げられます。
そのため、Pythonを習っていると出てくるようにClass内の関数にはselfが入っていて、
Mike.greet()と書いた時には、引数を入れなくても、関数がエラーなく実行されます。
つまり、インスタンス化している時(Human('Mike').greet()
)には、教科書通り、greet()にselfの分の第1引数を書かなくてもよくなりますが、
インスタンス化しないでクラス内の関数を実行しようとする場合(Human.greet()
)には、selfの分引数が省略されるみたいなのも発生しないんです。
まとめると
こんな感じになります
●【パターン1】
SomeClass().some_func(arg)
→インスタンス化しているから、呼び出したクラス内の関数のselfはクラス変数を参照する
●【パターン2】
SomeClass.some_func(arg1)
→インスタンス化していない(クラスの中の関数に直接アクセスしているだけ)から、呼び出したクラス内の関数のselfは第1引数としてarg1を参照する
余談
個人的にはライブラリ的な扱いとして、SomeClass.some_func(arg1)
みたいな書き方ができるようにプロジェクト作ってもいいのでは?とも一瞬思いましたが、
考えてみれば根本的なPythonのお作法から外れてみっともない気もするので、しっかりインスタンス化した方が望ましいと感じています。
ご拝読ありがとうございます!
追記
SomeClass.some_func(arg1)
をPython本来の書き方で実現したい場合は@staticmethod
のデコレータが使えました!
こちらで頂いたコメントにてお教えいただきました。
勉強になります、ありがとうございます...!