2.21. メソッドと属性

メソッド は、クラスの内部で定義された関数です。最初のパラメータは、そのメソッドが呼び出されるインスタンスです。慣例として、それは self と名付けられます。

2.21.1. インスタンスメソッド

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def magnitude(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

p = Point(3, 4)
print(p.magnitude())

出力:

5.0

p.magnitude() という呼び出しは、pself として自動的に渡します。メソッドの本体は、関数がパラメータを通じて名前を読み書きするのと同じように、self を通じて属性を読み書きします。

2.21.2. インスタンス属性とクラス属性

self に割り当てられた属性 -- 通常は __init__ の中で -- は、その 1 つのインスタンスに属します。

a = Point(1, 2)
b = Point(10, 20)
a.x = 99
print(a.x, b.x)           # 99 10

a.xb.x は別々のストレージです。一方を変更しても、もう一方には影響しません。

クラス本体の中で、どのメソッドの 外側 でも割り当てられた名前は、そのクラスのすべてのインスタンスで共有されます。

class Counter:
    kind = "tally"        # class attribute -- shared

    def __init__(self):
        self.value = 0    # instance attribute -- per instance

a = Counter()
b = Counter()
print(a.kind, b.kind)     # tally tally
上部に共有メソッドとクラス属性「kind」を持つクラスのブロックがあり、 その下に 2 つのインスタンスのボックスがそれぞれ独自の「value」属性を 持っていて、各インスタンスからクラスへと向かう矢印がある様子。

クラス属性はクラス自体に存在し、共有されます。インスタンス属性は各インスタンスに存在します。

クラス属性は、インスタンス属性と同じ方法(a.kind)で到達できます。Python はまずインスタンスを調べ、次にクラスを調べます。a.kind に代入すると、クラスのものを覆い隠す新しい インスタンス 属性が作成され、b.kind はそのまま残ります。

すべてのインスタンスが同じように参照すべき定数やデフォルトには、クラス属性を使用してください。各オブジェクトが独自のコピーを所有すべき状態には、インスタンス属性を使用してください。

2.21.3. __str__ と __repr__

2 つの特殊メソッドが、インスタンスがどのように表示されるかを制御します。__str__print() で使われる「親しみやすい」文字列を返します。__repr__ は REPL やコンテナの表示の中で使われる「開発者向け」の文字列を返します。

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return "(" + str(self.x) + ", " + str(self.y) + ")"

    def __repr__(self):
        return "Point(" + str(self.x) + ", " + str(self.y) + ")"

p = Point(3, 4)
print(p)            # uses __str__
print([p, p])       # uses __repr__ inside the list

出力:

(3, 4)
[Point(3, 4), Point(3, 4)]

__repr__ だけが定義されている場合、print() はそれにフォールバックします -- そのため、よく書かれた __repr__ が 1 つあれば通常は十分です。親しみやすい形式が開発者向けの形式と異なって見えるべき場合にのみ、__str__ も定義してください。オブジェクトを再生成する呼び出しのように見える __repr__ を目指してください。表示される値が曖昧でなければ、デバッグは劇的に楽になります。