質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.48%

クラスメソッドの用途がわからない

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 328

score 35

クラスメソッドの用途がわからないです。

Pythonのクラスメソッド(@classmethod)とは?使いどころとメソッドとの違いを解説
を見て、クラスメソッドの用途を勉強しています。

class Item:
    def __init__(self, id, name):
        self.id = id
        self.name = name

    @classmethod
    def retrieve_from_api(cls, id):
        res = requests.get(f"https://api.example.com/items/{id}")
        data = res.json()
        return cls(id, data["name"])


ならimport Item としたときにまとめてインポートできるが、

class Item:
    def __init__(self, id, name):
        self.id = id
        self.name = name


def retrieve_item(id):
    res = requests.get(f"https://api.example.com/items/{id}")
    data = res.json()
    return Item(id, data["name"])


ならまとめてインポートできない、だから便利、と言う説明なのですが、なら

class Item:
    def __init__(self, id, name):
        self.id = id
        self.name = name

    def retrieve_from_api(cls, id):
        res = requests.get(f"https://api.example.com/items/{id}")
     #以下省略


で良いのでは?と思います。
一番最後のようなコードではいけない理由を教えてください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+3

そのクラスのインスタンスを返す、ある種の特殊なコンストラクタとして使うのが、実用的な用途の一つだと思います(それがすべてではないと思いますが、一例として書いてみます)。

組み込み型のドキュメントにあるかな、と思って探したら、一番最初に見つかったのはこれでした。

classmethod int.from_bytes(bytes, byteorder, *, signed=False)
与えられたバイト列の整数表現を返します。

>>> int.from_bytes(b'\x00\x10', byteorder='big')
16
>>> int.from_bytes(b'\x00\x10', byteorder='little')
4096
>>> int.from_bytes(b'\xfc\x00', byteorder='big', signed=True)
-1024
>>> int.from_bytes(b'\xfc\x00', byteorder='big', signed=False)
64512
>>> int.from_bytes([255, 0, 0], byteorder='big')
16711680

組み込み型 — Python 3.9.4 ドキュメント | int.from_bytes

こういうのは関数よりはメソッドにしたが使いやすいですし、コンストラクタに直接実装するとコードの見通しが悪くなります。ということでクラスメソッドが適当な感じがします。


ということは質問者さんの参考にしているページにも書いてあるな……とあとから見て思ったので、ちょっと追記。

クラスメソッドはクラス自身を第一引数に取れます。なので、clsを使って何らかの処理を行うようなクラスメソッドであれば、サブクラスから呼び出した場合も適切に機能することが期待できる、というのは、関数にはないメリットと言えると思います。

class Hoge:
    ほにゃらら

class Fuga:
    @classmethod
    def from_hoge(cls, hogeobj):
        hogeobjを加工したりとか色々する
        return cls(ほにゃらら)

という感じの定義があったときに、

class FugaX(Fuga):
    ほにゃらら

class FugaY(Fuga):
    ほにゃらら

class FugaZ(Fuga):
    ほにゃらら

hoge = Hoge()
fx = FugaX.from_hoge(hoge)  # fxはFugaXのインスタンスになる
fy = FugaY.from_hoge(hoge)  # fyはFugaYのインスタンスになる
fz = FugaZ.from_hoge(hoge)  # fzはFugaZのインスタンスになる

ということができるという理屈です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/05/05 20:57

    ありがとうございます。ちょっと質問させてください。「こういうのは関数よりはメソッドにしたが使いやすいです」とありますが、関数=メソッドではないのでしょうか?詳細に言うと関数と呼ぶ言語とメソッドと呼ぶ言語に分かれていると言う認識です。
    また「なので、clsを使って何らかの処理を行うようなクラスメソッドであれば、サブクラスから呼び出した場合も適切に機能することが期待できる」とありますが、clsを使って何らかの処理を行うようなクラスメソッドとは例えばどんな場合ですか?またサブクラスとは何を指していますか?

    キャンセル

  • 2021/05/05 21:42

    サブクラスは継承したクラスのことですよね!すみません

    キャンセル

  • 2021/05/06 11:53

    関数=メソッドではありません。それぞれ存在します。
    clsを使うケースとしては、回答のコードをご確認ください。

    キャンセル

  • 2021/05/11 16:33

    ありがとうございます、勉強になります

    キャンセル

0

一番最後のようなコードではいけない理由を教えてください。

このように定義すると、そのインスタンスメソッドを呼び出すために、少なくともひとつのインスタンスオブジェクトを作っておかなければならず、それは使いにくいからです。

本題ではありませんが

Pythonのクラスメソッド(@classmethod)とは?使いどころとメソッドとの違いを解説というサイトはPythonのことをわかっている人が書いているとは思えないですね。

クラスをインポートすれば使える。

importするのは、モジュールやパッケージです。クラスをインポートするという言葉遣いは誤解を与えるので望ましくありません。

そのクラスを作るメソッドを書くことです。 

クラスを作るメソッドは存在しますが、ここに書かれている例はクラスを作るメソッドではありません。

結論:こういうサイトは参考にしない方が良いですよ。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-1

一番最後のようなコードではいけない理由を教えてください。

インスタンスメソッドは、Itemのインスタンスを作らないと呼び出せません。クラスメソッドなら、インスタンスを用意しなくてもいきなりItem.retrieve_from_apiとできます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る