1. ホーム
  2. python

[解決済み] 初心者のための@classmethodと@staticmethodの意味?[重複あり]

2022-03-17 11:05:53

質問

の意味を誰か説明してください。 @classmethod@staticmethod をpythonで使うことはできますか?その違いと意味を知りたいのです。

私が理解している限りでは @classmethod は、そのメソッドがサブクラスに継承されるべきメソッドであることをクラスに伝えるとか...。しかし、その意味は何だろう?なぜ、クラスメソッドを定義するだけで @classmethod または @staticmethod または任意の @ の定義は?

tl;dr: いつ を使うべきでしょうか。 なぜ を使うべきであり どのように を使うべきでしょうか?

どのように解決するのですか?

しかし classmethodstaticmethod は非常によく似ていますが、両エンティティの使い方に若干の違いがあります。 classmethod は最初のパラメータとしてクラスオブジェクトへの参照を持たなければならないのに対して staticmethod は、パラメータを全く持たないことができます。

class Date(object):

    def __init__(self, day=0, month=0, year=0):
        self.day = day
        self.month = month
        self.year = year

    @classmethod
    def from_string(cls, date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        date1 = cls(day, month, year)
        return date1

    @staticmethod
    def is_date_valid(date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        return day <= 31 and month <= 12 and year <= 3999

date2 = Date.from_string('11-09-2012')
is_date = Date.is_date_valid('11-09-2012')

説明

日付情報を扱うクラスの例を考えてみましょう(これが私たちの定型文になります)。

class Date(object):

    def __init__(self, day=0, month=0, year=0):
        self.day = day
        self.month = month
        self.year = year

このクラスは明らかに、特定の日付に関する情報を保存するために使用することができます(タイムゾーン情報なし。)

ここで __init__ という引数を受け取る、Pythonのクラスインスタンスの典型的なイニシャライザーです。 instancemethod を持ち、最初の非選択的引数 ( self ) は、新しく作成されたインスタンスへの参照を保持します。

クラスメソッド

を使うとうまくいく作業がいくつかあります。 classmethod s.

を大量に作りたい場合を考えてみましょう。 Date クラスのインスタンスは、外部ソースからの日付情報を 'dd-mm-yyyy' のフォーマットでエンコードした文字列として持っています。これをプロジェクトのソースコード内の異なる場所で行う必要があるとします。

では、ここでやらなければならないことは。

  1. 文字列を解析して、日、月、年を3つの整数型変数、またはその変数からなる3項目のタプルで受け取る。
  2. インスタンス化 Date 初期化呼び出しにそれらの値を渡すことによって。

このようになります。

day, month, year = map(int, string_date.split('-'))
date1 = Date(day, month, year)

このため、C++ではオーバーローディングでこのような機能を実装できますが、Pythonにはこのオーバーローディングがありません。その代わりに classmethod . もうひとつ、" を作ってみましょう。 コンストラクタ "です。

    @classmethod
    def from_string(cls, date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        date1 = cls(day, month, year)
        return date1

date2 = Date.from_string('11-09-2012')

上記の実装をより注意深く見て、どのような利点があるのかを確認してみましょう。

  1. 日付文字列のパースを一箇所にまとめて実装したので、再利用が可能になりました。
  2. ここではカプセル化がうまく機能しています(文字列解析を別の場所で1つの関数として実装できると考えると、この解決策はOOPパラダイムにはるかに適合しています)。
  3. cls を保持するオブジェクトです。 クラスそのもの であって、クラスのインスタンスではありません。これはとても素晴らしいことです。 Date クラスでは、すべての子クラスが from_string も定義されている。

静的メソッド

についてはどうでしょうか。 staticmethod ? とよく似ていますね。 classmethod が、(クラスメソッドやインスタンスメソッドのように)義務的なパラメータは取りません。

次のユースケースを見てみましょう。

何らかの方法で検証したい日付文字列があります。このタスクも論理的に Date クラスをインスタンス化する必要はありません。

ここで staticmethod が便利です。次のコードを見てみましょう。

    @staticmethod
    def is_date_valid(date_as_string):
        day, month, year = map(int, date_as_string.split('-'))
        return day <= 31 and month <= 12 and year <= 3999

    # usage:
    is_date = Date.is_date_valid('11-09-2012')

の使い方からわかるように staticmethod 基本的には単なる関数で、構文的にはメソッドのように呼び出されますが、オブジェクトとその内部(フィールドや別のメソッド)にアクセスすることはできません。