Skip to content
This page has been auto-translated and may contain errors.View in English

クラスとオブジェクト

docs.scrimba.com

これまでに使ってきたあらゆる型(文字列リスト辞書)は実はクラスです。"hello".upper()を呼び出すとき、文字列オブジェクトのメソッドを呼び出しています。クラスを使うと、独自の型を定義でき、独自のデータと動作を持たせることができます。Playerクラスは名前、スコア、レベルを保持でき、自分自身の表示方法を知っています。

クラスはユーザー定義型のメカニズムです。クラスはテンプレートを定義します:各インスタンスが保持するデータ(その属性、そのオブジェクトに格納されている値)と、サポートする操作(そのメソッド、それに付属している関数)です。値を並列変数で追跡して至る所に渡す代わりに、明確なインターフェースを持つ1つのオブジェクトにバンドルします。

class文は新しい(str と int のような、カスタム値の種類)を構築し、他のあらゆる代入と同様に名前にバインドします。インスタンス(その型の1つの具体的なオブジェクト)を作成するには、クラスを呼び出します:Player("太郎")。その呼び出しの背後で、Pythonは空白のオブジェクトを割り当て、__init__を実行してそれを満たします。モデルは全く同じです:クラス自体はオブジェクトであり、変数に格納したり、関数に渡したり、実行時に検査したりできます(プログラムの実行中)。これが、この章の後半の代替コンストラクタとレジストリを可能にします。

ブループリントとインスタンス

クラスはブループリント(設計図)です。インスタンスはそのブループリントから作られた具体的なもの(実体)です。必要に応じて何個でもインスタンスを作成できます。各インスタンスは独自のデータを持ちながら、クラスで定義されているメソッドを共有します。

クラスは構造と動作を定義します。インスタンスはそのクラスから作成されたオブジェクトです:各オブジェクトは独自のデータを持ちながら、クラスのメソッドオブジェクトを共有します。インスタンスを作成するには、クラスを関数のように呼び出します:Dog()は新しいDogインスタンスを作成します。

クラスを呼び出すことは順番に2つのことを行います:空白のインスタンスを割り当て、次に__init__を実行してデータを満たします。完成したオブジェクトは自分のクラスを記憶します(type(レックス)として読み直すことができます)。この関連付けは、レックス.bark()を呼び出すときにPythonがメソッドを見つける方法です:まずインスタンスを見て、次にクラスを見ます。実用的なポイントは、メソッドは1つの場所(クラスで共有)に存在し、データはインスタンスごとに存在するため、千個のDogオブジェクトは千個のデータセットの費用がかかりますが、各メソッドは1つのコピーしかありません。

python
class Dog:
    def bark(self):
        print("Woof!")

rex = Dog()
luna = Dog()

rex.bark()    # "Woof!"
luna.bark()   # "Woof!"

Dogはクラスです。rexlunaはインスタンスです:2つの異なる犬で、クラスで定義されている同じ動作を共有しています。

Junoブループリントとインスタンス クラスはブループリント(設計図)で、インスタンスはそれから構築されたもの(実体)です。クラスを関数のように呼び出すとDog()、新しいインスタンスが返されます。すべてのインスタンスはクラスのメソッドを共有しながら、独自のデータを保つため、レックスルナは同じように動作しながら別の犬になります。
JunoブループリントとインスタンスDog()を呼び出すとインスタンスが作成されます:独自のデータ、クラスの共有メソッド。そのバンドルが全体の要点で、関連する値とそれに作用するコードが一緒に移動し、手動で渡す個別の変数としてではありません。
Junoブループリントとインスタンス クラスを呼び出すと空白のオブジェクトが割り当てられ、次に__init__が実行されます。メソッドはクラスに1回だけ存在して共有され、データはインスタンスごとに存在するため、レックスでのメソッド呼び出しはインスタンスを見て次にクラスを見ることで見つかります。その分割により、数千のインスタンスも低コストのままです。

__init__self

__init__は、新しいインスタンスを作成するときにPythonが自動的に呼び出すメソッドです。オブジェクトの開始データを設定する場所です。selfは、メソッドが操作している特定のインスタンスを参照する方法で、常に最初のパラメーターです。

__init__は新しく割り当てられたインスタンスを初期化します。selfはすべてのインスタンスメソッドの最初のパラメーターの慣例的な名前です。alice.display()を呼び出すとき、Pythonはインスタンスを自動的にselfとして渡します。__init__内のselfに設定されている属性はインスタンス属性です:各インスタンスは独自のコピーを持ちます。

__init__は既に割り当てられたインスタンスで実行され、それをセットアップします。selfはキーワードではなく、最初のパラメーターで、Pythonがそれを埋めてくれます:alice.display()を呼び出すとき、Pythonは舞台裏でaliceselfとして渡します。self.attr = valueに設定することは、そのオブジェクトに書き込むため、2つのPlayerオブジェクトが互いのデータを踏み越すことはありません。より厳格な言語から来た人を驚かせることの1つは、Pythonは属性を任意の場所で追加することを許可し、__init__内だけではないということです。そのため、self.scor = 0のようなタイプミスは新しい属性を作成し、例外を発生させます。インスタンスが使用するすべての属性を__init__で設定し、Noneにしても、オブジェクトの形状は1つの場所で宣言され、タイプミスは他の場所で目立ちます。

python
class Player:
    def __init__(self, name, score=0):
        self.name = name
        self.score = score

    def add_points(self, points):
        self.score += points

    def display(self):
        print(f"{self.name}: {self.score} points")

alice = Player("太郎")
bob = Player("花子", score=50)

alice.add_points(30)
alice.display()   # "太郎: 30 points"
bob.display()     # "花子: 50 points"

self.nameself.scoreインスタンス属性です:特定のオブジェクトに属し、クラス自体ではなく。各Playerインスタンスは独自のnamescoreを持ちます。

Juno__init__と self__init__はインスタンスを作成する瞬間に実行されるため、self.name = valueで開始データを設定する場所です。selfはPythonが作業しているインスタンスで、常にメソッドの最初のパラメーターで、自動的に渡されます。alice.display()を呼び出すときに、self自体を渡すことはありません。
Juno__init__と self__init__は新しいインスタンスをセットアップし、そこでselfに格納するあらゆるものはインスタンス属性で、オブジェクトごとに1つのコピーです。selfはすべてのインスタンスメソッドの最初のパラメーターです。alice.display()を記述するときにPythonがインスタンスを渡し、定義でのみそれを名前付けします。
Juno__init__と selfselfはインスタンスで、すべての呼び出しで渡され、self.attrへの書き込みはそのオブジェクトに着地します。Pythonは`__init__`の外に属性を追加することを止めないため、スペルを間違えたself.scorは静かに新しい属性を作成します。すべての属性を__init__で宣言し、Noneとしても、タイプミスは隠れる場所がありません。

メソッド

クラス内で定義される任意の関数メソッドです。インスタンスメソッドは常に最初のパラメーターとしてselfを持ちます;Pythonはそれを自動的に渡します。メソッドはself経由でインスタンスのデータを読取および変更できます。

インスタンスメソッドはクラスに格納された通常の関数です。instance.methodにアクセスするとき、Pythonはバインドメソッドを返します:selfとして既にインスタンスが接続された同じ関数で、残りの引数だけを渡します。メソッドからselfを返すことはチェーニングを可能にします:obj.scale(2).rotate(90)

メソッドはクラスの1つの関数で、すべてのインスタンスで共有されます。c.scaleにアクセスすることは、生の関数を返しません、バインドメソッドを返します:その同じ関数でcが既にselfとして接続されており、これはselfを渡さずにどのように渡されるかです。実コードで報酬を得る2つのパターン。ミューテーティングメソッドからselfを返すと、流暢なインターフェースc.scale(2).scale(0.5)のようなチェーンされた呼び出し)が得られます;それをビルダースタイルのオブジェクトに予約します。チェーニングが良く読めるときだけで、selfを返すメソッドと新しい値を返すメソッドは呼び出し場所で同じに見えるため、すべてには予約しません。そしてバインドメソッドが第一級値であるため、1つを格納できます(handler = obj.save)して後で呼び出し、これはコールバックとイベントハンドラーが依存するものです。

python
class Circle:
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14159 * self.radius ** 2

    def scale(self, factor):
        self.radius *= factor
        return self    # self を返すことでチェーニングが可能になります: c.scale(2).scale(0.5)

c = Circle(5)
print(c.area())    # 78.53975
c.scale(2)
print(c.area())    # 314.159
Junoメソッド メソッドはクラス内で定義された関数で、その最初のパラメーターは常にselfで、それが作用しているインスタンスです。Pythonはselfを渡すため、追加なしでc.area()を呼び出します。selfを通じて、メソッドはそのオブジェクト独自のデータを読取および変更します。
Junoメソッド メソッドはクラスの平文な関数です。インスタンス経由でそれらに到達すると、selfが自動的にバインドされ、残りだけを渡します。チェーニングのようにc.scale(2).scale(0.5)にしたいときはselfを返します。それ以外は呼び出し元が求めた値を返します。
Junoメソッドobj.methodはバインドメソッドを提供し、objselfとして接続された関数で、これが渡す理由です。selfを返すと流暢なチェーニングが得られ、ビルダーにとって価値がありますが、混乱しているすべてのメソッドがそれを行う場合。そしてバインドメソッドが値であるため、handler = obj.saveは後でコールバック用にそれを保存します。

クラス変数とインスタンス変数

クラスに直接定義された変数(__init__内ではなく)はクラス変数です。すべてのインスタンスは同じクラス変数を共有します。__init__内のselfに設定された変数はインスタンス変数で、各オブジェクトに固有です。

クラス変数はクラスに1回格納され、すべてのインスタンスで共有されます。インスタンス変数は個別のオブジェクトに格納されます。self.attrを読むとき、Pythonはまずインスタンスをチェックしてからクラスをチェックします。self.attr = valueに書き込むとき、それは常にインスタンス独自のコピーを作成または更新し、そのオブジェクトのみのクラス変数を隠します。

self.attrを読むことはインスタンスをチェックしてからクラスをチェックするため、クラス変数はいくつかのインスタンスが独自の値を書き込んでそれを隠すまでの共有デフォルトとして機能します。本番で逆転するトラップはミューテーション可能なクラス変数(リストや辞書のようにインプレースで変更できるもの)です。self.x = ...を割り当てるとプライベートコピーが作成されますが、self.x.append(...)ではありません:1つの共有オブジェクトに到達し、すべてのインスタンスが変更を見ます。インスタンスごとに新しいリストが必要な場合は、self.history = []__init__で構築し、クラスレベルのhistory = []としてはいけません。クラス変数を本当に共有されるもの、それらを不変にしておいてください:定数、デフォルト、カウンター。

python
class Player:
    max_lives = 3    # クラス変数、すべての Player に同じ

    def __init__(self, name):
        self.name = name   # インスタンス変数、各 Player に固有
        self.lives = Player.max_lives

    def die(self):
        self.lives -= 1

alice = Player("太郎")
bob = Player("花子")

Player.max_lives = 5    # 現在および将来のすべてのインスタンスのために変更

クラス変数をすべてのインスタンスで共有される値に使用します:定数、カウンター、デフォルト。インスタンス変数をオブジェクトごとに異なるデータに使用します。

Junoクラス変数とインスタンス変数 クラスに直接設定された変数はすべてのインスタンスで共有されます;__init__selfに設定された変数はそのオブジェクトに属します。self.attr = valueを書き込むことは常にインスタンス独自のコピーを作成または更新します。そのため、値がすべての人で同じときはクラス変数に到達し、オブジェクトごとに異なるときはインスタンス変数に到達します。
Junoクラス変数とインスタンス変数self.attrを読むことはインスタンスをチェックしてからクラスをチェックするため、クラス変数は共有デフォルトです。self.attr = valueを書き込むことは常にインスタンスに着地し、そのオブジェクトのクラス変数を隠します。定数とデフォルトにクラス変数を保つ、オブジェクトごとの状態はselfに送ります。
Junoクラス変数とインスタンス変数 静かなバグはミューテーション可能なクラス変数です:self.x = ...はプライベートコピーを作成しますが、self.x.append(...)は1つの共有オブジェクトをミューテーションするため、すべてのインスタンスがそれを見ます。インスタンスごとのリストが必要な場合は、self.history = []__init__で構築し、クラスレベルでhistory = []としてはいけません。

__str____repr__

__str__は、print()と f-strings がオブジェクトに対して表示するものを制御します。__repr__は、コンソールで表示され、デバッグするための開発者ビューを制御します。常に__repr__を定義してください。__str__を定義して、デバッグビューとは別の清潔なユーザー向けディスプレイが必要なときに。

__str__str()print()、および出力チャプターからのf-stringsで呼び出される、ユーザー向けテキスト。__repr__repr()で呼び出され、コンソール内のオブジェクトの表示時に表示されて、開発者ビュー。__repr__のみが定義されている場合、Pythonはそれを両方に使用します。慣例:__repr__はオブジェクトを再作成するコードのように見える文字列を返し;__str__は読める概要を返します。

これらは2つのダンダーメソッド(ダブルアンダースコアの短縮:先頭と末尾の__で名付けられたメソッドで、Pythonが適切な瞬間に呼び出します)。print(obj)str(obj)__str__を呼び出し、__str__がないときは__repr__に戻ります。repr(obj)、およびコンソールで裸で表示されるオブジェクトは、__repr__を呼び出します。そのため__repr__は常に仕事を持つ1つで、その理由がルール:常に__repr__を定義し、ユーザー向けテキストがデバッグテキストと異なるべき場合のみ__str__を追加します。__repr__をオブジェクト(Player(name='太郎', score=87))を構築したコンストラクター呼び出しのように見えるようにし、フィールドで!rを使用し、文字列はそれらの引用符を保つため、迷子の空間または改行は隠すのではなく表示されます。良い__repr__は、午前2時でログラインまたはスタックトレースを読める理由です。

python
class Player:
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def __str__(self):
        return f"{self.name} ({self.score} pts)"

    def __repr__(self):
        return f"Player(name={self.name!r}, score={self.score})"

alice = Player("太郎", 87)
print(alice)        # "太郎 (87 pts)"   (__str__ を使用)
repr(alice)         # "Player(name='太郎', score=87)"  (__repr__ を使用)

常に__repr__を定義します。デバッグビューとは別に清潔なユーザー向け表現が必要なときは__str__を定義します。__repr__のみが定義されている場合、Pythonはそれを両方に使用します。

Juno__str__と__repr____str__print()と f-strings が表示するもの、フレンドリー版です。__repr__は開発者ビューで、コンソールで見えるものです。常に__repr__を書いてください;`__str__`を忘れた場合でも仕事を持つ1つです。ユーザー向けテキストが異なるように読むべきときのみ__str__を追加します。
Juno__str__と__repr____str__print()と f-strings の読める版です;__repr__はデバッグ版で、__str__がないときにPythonはそれに戻ります。常に__repr__を定義し、オブジェクトを構築した呼び出しのように見えるようにし、後でオブジェクトがログに表示されるときに自分自身を救います。
Juno__str__と__repr____repr__は常に仕事を持つ、__str__は用户ビューが異なるべきときのみ、そのため毎回__repr__を定義します。コンストラクターのようにそれをシェイプし、フィールドに!rを置き、迷子の空間または改行が隠れる代わりに表示されるようにします。その1つの習慣が午前2時のスタックトレースを読める理由です。

プライベート規約

Pythonには本当のプライベート変数がありませんが、名前の開始時に1つのアンダースコア(_balance)は「これは内部で、クラスの外から直接使用しないでください」を合図する規約です。言語によって強制されません;これは他の開発者へのコミュニケーションです。

1つのアンダースコア(_attr)は内部使用を合図する規約です。Pythonはそれを強制しません、すべてのリンター、IDE、開発者がそれを尊重します。ダブルアンダースコア(__attr)トリガー名前マングリング:Pythonはそれを_ClassName__attrに書き直し、サブクラスでの偶然の衝突を防止します。これは真のプライバシーではなく;衝突回避メカニズムです。

1つのアンダースコアは規約のみです:何も強制しません、ただしリンター(コードをスタイルとおそらくバグについてスキャンするツール)、編集者、レビュアーはすべて_balanceを「内部、外から触らないでください」として読みます。ダブルアンダースコアトリガー名前マングリング:Pythonは__attr_ClassName__attrに書き直すため、サブクラスが独自の__attr__を定義することは親と偶然クラッシュできません。これは衝突ガード、プライバシーではありません:マングルされた名前はまだ誰かが主張する場合外から到達可能です。広くサブクラスされることを意図する基本クラス内でのみそれに到達し、サブクラスがステップオンできない属性が必要な場合があります;通常のコード内、単一のアンダースコアは正しいデフォルトで、ダブルアンダースコアはほとんど混乱を作成するだけです。任意の属性が設定されるのを止めたい場合(前の迷子のself.scor)、固定属性名のリストで__slots__を定義します:これはインスタンスが持つ可能性がある唯一の属性がそれらであることをPythonに伝え、他のあらゆる割り当ては静かに貼り付けるのではなく発生します、そしてそれはボーナスとしてインスタンスごとのメモリを減らします。

python
class BankAccount:
    def __init__(self, balance):
        self._balance = balance    # _ は「触らないでください」を意味します

    def deposit(self, amount):
        if amount > 0:
            self._balance += amount

    def balance(self):
        return self._balance

ダブルアンダースコア(__name)はトリガー名前マングリング;Pythonは属性を_ClassName__nameに名前変更して、サブクラス内の衝突を回避します。これはめったに必要ありません。シングルアンダースコアはほとんどのコードの規約です。

Junoプライベート規約 Pythonには本当のプライベート変数がありませんが、先頭のアンダースコア(_balance)は「内部、外から放っておいてください」の合意された合図です。何も止めません。これは他の開発者、将来あなたへのメッセージです。ダブルアンダースコアはサブクラス内で名前の衝突を回避するためのまれなツール;シングルアンダースコアは日々使うものです。
Junoプライベート規約 シングルアンダースコアは「内部」を意味し、すべてのツールとレビュアーはそれを尊重します。Pythonはそれを強制しませんが。ダブルアンダースコアは_ClassName__attrにマングリングを名前変更し、アクセスではなくサブクラス名の衝突に対するガード。デフォルトではシングルアンダースコアに到達します;ダブルはまれです。
Junoプライベート規約 シングルアンダースコアは規約で、ダブルアンダースコアはサブクラスの衝突を止めるために_ClassName__attrにマングリング、どちらも本当のプライバシーではありません。広くサブクラスされるベースクラスのために__attrを保つ;他の場所はそれ混乱を追加するだけです。迷子の属性を禁止したく、タイプミスのself.scorをキャッチしたい場合は、固定リストに__slots__を設定します。

継承

クラスは別のクラスから継承でき、自動的にすべての属性とメソッドを取得します。その後、サブクラスで特定のメソッドをオーバーライドして、それらの動作を変更できます。これにより、一般的なベースを再利用し、必要に応じて特殊化できます。

継承は「is-a」関係をモデル化します:DogAnimalです。サブクラスは親のすべてのメソッドと属性を取得し、独自のバージョンを定義することでそれらのいずれかをオーバーライドできます。メソッドを呼び出すとき、Pythonはサブクラスで最初に見て、次に親を上に歩くため、オーバーライドされていないメソッドは自動的に落ちます。その検索パスはメソッド解決順序(MRO)で、Pythonが検索するクラスの順序付きリスト。

obj.methodを呼び出すとき、Pythonは固定順序内のクラスを検索し、MRO(メソッド解決順序:クラスとその祖先のフラット化されたリスト、Dog.__mro__として読める)を検索し、最初のマッチを使用します。シングル継承は直接的で、サブクラスは親です。MRO が存在する理由は複数の継承とダイアモンドケース(2つの親の両方が一般的な祖父母から継承)です:Pythonはクラスを順序付けるため、祖父母は一度表示され、両親の後で、呼び出しを決定的に解決します。実用的な指導:浅い階層とシングル継承を好みます。深い、または複数の継承ツリーは「実際にどのメソッドが実行されました」を推論するのが難しくなるため。複数のベースを混ぜるときは、各__init__super()(次のセクション)を通じてルーティングします。そのため、各1つは正確にその順序に沿って実行されます。

python
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return "..."

class Dog(Animal):
    def speak(self):
        return f"{self.name} says Woof!"

class Cat(Animal):
    def speak(self):
        return f"{self.name} says Meow!"

pets = [Dog("レックス"), Cat("ルナ"), Dog("マックス")]
for pet in pets:
    print(pet.speak())

DogCatAnimalから__init__を継承するため、それら独自が必要ありません。それらspeak()をその特定の動作でオーバーライドします。

Juno継承 サブクラスは親が持つあらゆるものを継承し、変更したいメソッドのみをオーバーライドします。オーバーライドしないあらゆるものは無料で親に落ちます。これが全体のポイント:共有動作を1回書き、それが異なるところで特殊化します。DogCatAnimal__init__を再利用し、speak()のみを再定義します。
Juno継承 継承は「is-a」です:サブクラスは親のメソッドを取得し、必要なものをオーバーライドし、オーバーライドされていない呼び出しは落ちます。Pythonはメソッドを MRO を歩いて見つけ、サブクラスを最初に、次に親に。共有ベースを再利用し、異なるものだけを再定義します。
Juno継承 Pythonは MRO を歩いて第1のマッチを取ることでメソッドを解決し、これはダイアモンドケースを決定的にします。階層を浅く保ち、シングル継承に頼ります。深い、または複数の継承ツリーは「どのメソッドが実行されました」を推測ゲームに変えます。ベースを混ぜる必要があるとき、すべての__init__super()を通じてチェーンします。

super()

super()は親クラスからメソッドを呼び出します。全く置き換えるのではなく、親の動作を拡張したいときはそれを使用します:親の__init__を呼び出して、そのセットアップを実行し、その後、サブクラスが必要なあらゆるものの上に追加します。

super()は MRO 内の次のクラスへのメソッド呼び出しを委譲するプロキシオブジェクトを返します。親が1つを持つときは、常にサブクラス__init__からsuper().__init__()を呼び出します。スキップすることは親のセットアップコードが実行されず、オブジェクトを壊れた状態に残す可能性があることを意味します。

super()は「私の直接の親」ではなく、「MRO に沿って次のクラス」(前のセクションからの検索順序)を意味します。プレーンサブクラス内、その次のクラスは親であり、区別は学術的に見えますが、複数継承を機能させる正確なものです:ツリーのあらゆるクラスがsuper().__init__(...)を呼び出す場合、各__init__は一度実行され、MRO 順序で、クラスがハードコード親を名前で、別のクラスが混ぜ込まれた瞬間チェーンを破壊でき、共有ベースを2回実行できる場合がありません。これはsuper().__init__()を記述する理由で、Animal.__init__(self)ではなく:親を直接命名することは別のクラスが混ぜ込まれた瞬間チェーンを破壊し、共有ベースを2回実行できます。ベアーsuper()引数なしが現代形です;古いsuper(Dog, self)は同じことを綴られたもので、古い版をターゲットするコード内でまだ見えます。

python
class Animal:
    def __init__(self, name, sound):
        self.name = name
        self.sound = sound

class Dog(Animal):
    def __init__(self, name):
        super().__init__(name, "Woof")   # Animal.__init__ を呼び出し
        self.tricks = []                  # 追加なにかを追加

    def learn(self, trick):
        self.tricks.append(trick)

rex = Dog("レックス")
rex.learn("sit")
print(rex.tricks)   # ["sit"]

サブクラスが独自の__init__を持ち、親もそうであるときはいつもsuper().__init__()を呼び出します。

Junosuper()super()は親クラスに到達するため、super().__init__()は自分の追加する前に親のセットアップを実行します。サブクラスが独自の__init__を書き、親も持つときはそれを使用します。スキップすることは親のセットアップが実行されず、オブジェクトを半構築のままにする可能性があることを意味します。
Junosuper()super()は次のクラスに委譲するため、親が1つを持つときは常にサブクラス__init__からsuper().__init__()を呼び出します。それを忘れて、親のセットアップがスキップされ、オブジェクトを壊れた状態に残す可能性があります。それはサブクラスがそれが拡張する親に接線するラインです。
Junosuper()super()は「私の親」ではなく「MRO 内の次のクラス」を意味し、ハードコードAnimal.__init__(self)がクラスが混ぜ込まれた場合チェーンを破壊する理由です。すべての__init__super()を呼び出す場合、各1つは順序に沿って実行されます。ベアーsuper()が現代形です;super(Dog, self)は同じことを綴られたものです。

クラスメソッドと静的メソッド

@classmethodはインスタンスの代わりにクラス自体を受け取るメソッドを作成します。文字列、ファイル、または別の形式からインスタンスを作成する代替コンストラクターに有用です。@staticmethodは組織的な理由でクラス内に住んでいるプレーンな関数です;インスタンスもクラスも受け取りません。

@classmethodはインスタンスではなく最初の引数としてクラス(cls)を受け取ります。主な使用法は、異なる入力形式からインスタンスを作成する代替コンストラクターです。@staticmethodは、クラスで命名空間化されたレギュラー関数です;クラスまたはインスタンスへのアクセスはありません。@classmethodをコンストラクターに、@staticmethodをクラスに論理的に結びついたユーティリティ関数に使用します。

@classmethodはインスタンスではなく、最初の引数としてクラス(cls)を受け取ります。そして、稼ぐ詳細はclsが定義された場所ではなく、呼び出されたクラスであることです。そのためPlayer.from_stringcls(...)で構築され、サブクラスProPlayerProPlayer.from_string(...)を呼び出す場合、それはPlayerではなくProPlayerを構築します。これが代替コンストラクターが、クラス名をハードコード代わりに@classmethodを使用する正確な理由です:それらは継承の下で機能し続けます。@staticmethodはインスタンスもクラスも取りません;それはクラスの下に駐車された平文な関数で、命名空間のために、ロジックがクラスに属することは何もその行き来もありません。classmethod を使用してインスタンスをいくつかの他の形式から作成するとき、staticmethod を関連するヘルパーのために、通常のメソッドを1つのオブジェクトのデータに触れるあらゆるもののために。

python
class Player:
    def __init__(self, name, score):
        self.name = name
        self.score = score

    @classmethod
    def from_string(cls, data):
        name, score = data.split(",")
        return cls(name, int(score))

alice = Player.from_string("太郎,87")
python
class Player:
    @staticmethod
    def is_valid_name(name):
        return name.isalpha() and len(name) >= 2

Player.is_valid_name("太郎")   # True
Player.is_valid_name("太郎1")      # False

代替コンストラクターのために@classmethodを使用します。クラスに論理的に属するがインスタンスまたはクラスデータを必要としないユーティリティ関数のために@staticmethodを使用します。

Junoクラスメソッドと静的メソッド@classmethodはインスタンスではなくクラスを手渡し、代替コンストラクターで行きます:文字列、ファイル、あらゆる形式のプレーヤーを構築します。@staticmethodは清潔さのためにクラスの中に詰め込まれたオーディナリー関数です;クラスもインスタンスも取りません。プレーンメソッドは1つのオブジェクトのデータに触れ、これら2つは接触しません。
Junoクラスメソッドと静的メソッド@classmethodclsを取り、クラス自体、代替コンストラクターのためにcls(...)を返すためにそれを使用します。@staticmethodは何も陰を取らない、クラス下で命名空間化されたヘルパー。メソッドはオブジェクト当たりのデータ、classmethod で構築するために、staticmethod を関連するヘルパーのために。
Junoクラスメソッドと静的メソッド classmethod コンストラクターのポイントは`cls`が誰が呼び出したかであること、そのため`ProPlayer.from_string(...)`は`Player`ではなく`ProPlayer`を構築します。クラス名をハードコード、あなたはそれを失う。Classmethod で構築するために、staticmethod を関連するヘルパーのためにデータが必要ない、通常のメソッドはインスタンスに触れるあらゆるもののためにします。

@property

@propertyはメソッドを属性のようにアクセスでき、括弧は必要なしで。他の属性から計算されたている値で、シンプルな属性アクセスのような読む自然に感じるためにそれを使用します。

@propertyはメソッドを読取専用属性に変えます。属性にアクセスすると、メソッドが実行されます。これは格納されたデータから派生した計算値に有用で、公開インターフェースを変更せずに属性アクセスに検証を追加するためにも有用です。ペアの@name.setterは属性を書き込み可能にします。

@propertyはメソッドを属性のような何かに変えます:c.area、括弧なし、メソッドを毎回実行時にアクセスを実行します。@area.setterを追加し、それは書き込み可能になります、その検証が入る場所(負の半径を拒否)。実際の値は、これが呼び出し元のために何も変わらないことです:プレーンself.radius属性で始めることができ、後で検証で属性を昇進させ、1つのラインをそれを読むまたはそれを書くに触れることなく。これはPythonが getter/setter セレモニーを持たない理由で、プレーン属性を公開し、1つが計算またはガード必要であるときのみ属性に到達します。本番のための2つの注意:アクセスは無料に見えますが、コードを実行し、それを安く保ちます(それをすべて読むことを再計算するのではなく、高価な結果をキャッシュ)、そして属性が静かに重い仕事をするまたは上げることが誰が単純なフィールドであると見なされたサプライズ。

python
class Circle:
    def __init__(self, radius):
        self.radius = radius

    @property
    def area(self):
        return 3.14159 * self.radius ** 2

    @property
    def diameter(self):
        return self.radius * 2

c = Circle(5)
print(c.area)      # 78.53975 (属性のように見える、メソッドのように実行する)
print(c.diameter)  # 10

属性は計算値に有用です:他の属性から派生するものは、()なしで属性として読む自然に感じるもの。

Juno@property@propertyはメソッドを属性のような読みできます、括弧なし:c.area()ではなくc.area。他の属性から働かされた値に合い、プレーンなデータとして読む自然に感じます。舞台裏、それはそれにアクセスするたびにあなたのメソッドを実行します。
Juno@property@propertyはメソッドを属性のような読みでき、ペアの@name.setterはそれを書き込み可能にして、あなたはその中で検証できます。勝利:プレーン属性を後で計算されたまたは検証されたものに変えることができ、変更呼び出し元なし。それが計算またはガード値のために使用、テンプレートの習慣ではありません。
Juno@property@propertyを好む理由:プレーン属性は後で計算されたまたは検証されたものに変わることができ、呼び出し元の変更なし、その時点でしか属性に到達しません。アクセスは無料に見えますが、コードを実行し、安く保ち、高価なものをキャッシュし、重い仕事またはフィールドのように見える背後の上げを隠しません。

実践

インスタンス属性、メソッド、@property__str__を持つPlayerクラス:

python
class Player:
    max_lives = 3

    def __init__(self, name: str):
        self.name = name
        self.score = 0
        self.lives = Player.max_lives

    def earn_points(self, amount: int) -> None:
        self.score += amount

    def take_hit(self) -> bool:
        self.lives -= 1
        return self.lives > 0

    @property
    def is_alive(self) -> bool:
        return self.lives > 0

    def __str__(self) -> str:
        return f"{self.name} | Score: {self.score} | Lives: {self.lives}"

alice = Player("太郎")
alice.earn_points(50)
alice.take_hit()
print(alice)            # "太郎 | Score: 50 | Lives: 2"
print(alice.is_alive)   # True

プライベート属性とともにUserクラス、@propertyゲッター、deactivateメソッド、およびto_dictシリアライザー:

python
class User:
    def __init__(self, user_id: int, username: str, email: str):
        self.id = user_id
        self.username = username
        self.email = email
        self._active = True

    @property
    def active(self) -> bool:
        return self._active

    def deactivate(self) -> None:
        self._active = False

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "username": self.username,
            "email": self.email,
            "active": self._active,
        }

    def __repr__(self) -> str:
        return f"User(id={self.id}, username={self.username!r})"

alice = User(1, "alice", "[email protected]")
print(alice.to_dict())
alice.deactivate()
print(alice.active)   # False

列車/検証スライシングを属性の背後に封じ込めるDataSplitクラス、クリーンなデバッグ出力のための__repr__で:

python
class DataSplit:
    def __init__(self, data: list, train_ratio: float = 0.8):
        split = int(len(data) * train_ratio)
        self._train = data[:split]
        self._val = data[split:]

    @property
    def train(self) -> list:
        return self._train

    @property
    def val(self) -> list:
        return self._val

    @property
    def sizes(self) -> tuple[int, int]:
        return len(self._train), len(self._val)

    def __repr__(self) -> str:
        return f"DataSplit(train={len(self._train)}, val={len(self._val)})"

data = list(range(100))
split = DataSplit(data, train_ratio=0.8)
print(split)         # DataSplit(train=80, val=20)
print(split.sizes)   # (80, 20)

_train_valの上のアンダースコアプレフィックスは、呼び出し元が生のリストを直接ミューテーションするのではなく属性を通じて行く信号です。Pythonはこれを強制しません、それは明確な契約を設定します。