PHPしか知らない僕がPythonを少し触ってみたよ 〜classmethodを使う〜

この記事はだいぶ前に書かれたものなので情報が古いかもしれません
僕が学生の頃はレギュラーが90円くらいだったんだけどな……

この記事を三行にまとめると

クラス変数を使う場合はselfが必要になります
デコレータってのは……何だろな
クラスメソッドは使い勝手が良いのかなあという気もします
pythonでクラスを使う時、メソッドの第一引数にはselfという、phpで言う$thisみたいなのを入れておくのが一般的だと思うのですが、必ずしも入れなきゃいけないわけではなく、それを必要とするパターンとそうじゃないパターンってのが存在します。

なので今日はそのパターンについて少しまとめておこうかと。



selfを使う

まずselfを第一引数に入れる場合。

class Sample() :
  def tax(self, price) :
    print(int(price * 1.1))

例えば引数に数字を渡すと税込価格を出力するクラスとメソッドがあったとします。

このメソッドを実行するにはこんな(↓)コードを書きます。

obj = Sample()
obj.tax(100)

これで画面に「110」が出力されます。メソッドに呼び出す際はselfを除外して第一引数にpriceを渡します。

selfは$thisのような働きをするので、例えばクラス変数を使う場合はselfが必要になります。

class Sample() :
  rate = 1.1

  def tax(self, price) :
    print(int(price * self.rate))

obj = Sample()
obj.tax(100)

こんな感じですね。特に難しいことはないと思います。

ただし第一引数にselfがある場合、下の書き方だとエラーになります。

Sample.tax(100)

こういうの何て言うかよく分からないんですけど……Sampleの後ろのカッコを省略すると「引数が足りねーよ」って言われちゃいます。カッコがあればオッケー。

Sample().tax(100)

たぶんカッコがあるとインスタンスの生成になって、カッコがない場合はクラスへの直のアクセス(スタティック)という違いだと思うんですが……そんでもってselfを使うはインスタンスの生成が必須とか、そんな感じじゃないでしょうか。間違えていたらごめんなさい。

一応、インスタンスを一度生成しておいて、それを第一引数に渡せばカッコなしで呼び出すこともできます。

obj = Sample() #インスタンスを生成
Sample.tax(obj, 100) #インスタンスを渡す

でもこの書き方をするなら「obj.tax()」と書く方が良さそうだよね……。

それから$thisのような働きはしますが、$thisと違うところはselfという単語じゃなくても良い点ですかね。selfと書くのが一般的ですが別に「myself」とか「yourself」とか「now_on_sale」とかでも動く。




selfを使わない

続いて引数にselfを入れない場合。

class Sample() :
  def tax(price) :
    print(int(price * 1.1))

obj = Sample
obj.tax(100)

selfがある場合とほとんど同じですが、こっちの場合はSampleの後ろにカッコがあるとエラーになります。ドットでつないで一行で書く場合も同様。

Sample.tax(100) #エラーにならない
Sample().tax(100) #エラーになる

それからselfがないとメソッドの中でクラス変数を使うことができません。

class Sample() :
  rate = 1.1

  def tax(price) :
    print(int(price * self.rate))

Sample.tax(100)

これだとselfは定義されてないぞというエラーが出てしまいます。かと言ってself.rateをただのrateに変えてもやっぱりそんな変数は定義されとらんわいと言われちゃいます。



classmethodを使う

これはPHPにはない書き方だと思うのですが、pythonのクラスでは上記以外にデコレータでclassmethodを定義するやり方があります。デコレータってのは……何だろな。ケーキの上に乗せるイチゴやホイップクリーム的なものじゃないとは思うんですが、とりあえず先頭に「@」をつける構文のことです。よく分かってないんで雑ですまん。

デコレータを使うとこういう書き方になります。

class Sample() :
  @classmethod
  def tax(cls, price) :
    print(int(price * 1.1))

まず関数の前に「@classmethod」というコードをつけ足します。これでtax()がクラスメソッドになります。それから第一引数に「cls」という変数がありますが、これはselfと似たようなもので$this的な扱いができます。これもclsと書くのが一般的らしいですが別に「cia」とか「fbi」とか「usa」とかでも動きます。

selfと同じで関数を呼び出す時はclsを除外します。

class Sample() :
  @classmethod
  def tax(cls, price) :
    print(int(price * 1.1))

obj = Sample()
obj.tax(100)

クラスメソッドの良いところ(?)は、selfと同様にクラスメソッドが使えることとカッコがあってもなくても動くことでしょうか。

class Sample() :
  rate = 1.1

  @classmethod
  def tax(cls, price) :
    print(int(price * cls.rate))

Sample.tax(100) #動く
Sample().tax(100) #動く

ただしinit関数を使用する場合はカッコつきでなおかつinit関数もクラスメソッドにしておく必要があります。

class Sample() :
  rate = 0

  @classmethod
  def __init__(cls) :
    cls.rate = 1.1

  @classmethod
  def tax(cls, price) :
    print(int(price * cls.rate))

Sample.tax(100) #0
Sample().tax(100) #110

カッコなしでもエラーにはなりませんが、initが読み込まれないのでrateが初期値の0のままになり、正しい計算結果になりません。またinitにデコレータがない場合もエラーにはならないですがrateは0のままです。

class Sample() :
  rate = 0

  def __init__(cls) :
    cls.rate = 1.1

  @classmethod
  def tax(cls, price) :
    print(int(price * cls.rate))

Sample().tax(100) #0



staticmethod

もう一つデコレータを使うパターンにスタティックメソッドというのがあります。

class Sample() :
  @staticmethod
  def tax(price) :
    print(int(price * 1.1))

Sample.tax(100) #動く
Sample().tax(100) #動く

@classmethodと同じように「@staticmethod」で定義します。スタティックメソッドはselfやclsなどが使えないのでクラス変数も使えません。呼び出す時はカッコありなしどちらもで動きます。






どれが良いんだって言われると、状況に応じて使い分けるのが良いって答えになるんでしょうけど、でも僕の場合、呼び出す時のカッコのつけ忘れって結構あったりするので、クラスメソッドは使い勝手が良いのかなあという気もします。

でもinitでわちゃわちゃと初期設定をするならselfを使った方が良さそうだし……やっぱり状況に応じてって感じですかね。
 もしかしたら何か関連しているかも? 
 質問や感想などお気軽にコメントしてください