2.21. Metody a atributy

Metoda je funkce definovaná uvnitř třídy. Prvním parametrem je instance, na níž je metoda volána; konvencí je pojmenovat jej self.

2.21.1. Instanční metody

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())

Výstup:

5.0

Volání p.magnitude() automaticky předá p jako self. Těla metod čtou a aktualizují atributy skrz self stejně, jako funkce čtou a aktualizují jména skrz parametry.

2.21.2. Instanční vs. třídní atributy

Atributy přiřazené k self – typicky uvnitř __init__ – patří té jedné instanci:

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

a.x a b.x jsou různá úložiště; mutace jednoho neovlivní druhé.

Jména přiřazená v těle třídy, mimo jakoukoli metodu, sdílí každá instance dané třídy:

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
Blok třídy nahoře držící sdílené metody a třídní atribut "kind"; pod ním dvě krabice instancí, z nichž každá drží svůj vlastní atribut "value", se šipkami vedoucími od každé instance nahoru ke třídě.

Třídní atributy žijí na samotné třídě a jsou sdílené. Instanční atributy žijí na každé instanci.

K třídnímu atributu se přistupuje stejně jako k instančnímu (a.kind); Python hledá nejprve na instanci, pak na třídě. Přiřazení k a.kind by vytvořilo nový instanční atribut, který zastíní ten třídní, a b.kind by nechalo nedotčené.

Třídní atributy používejte pro konstanty a výchozí hodnoty, které má každá instance vidět stejně. Instanční atributy používejte pro stav, jehož vlastní kopii má vlastnit každý objekt.

2.21.3. __str__ a __repr__

Dvě speciální metody řídí, jak se instance vypisuje. __str__ vrací „přátelský“ řetězec používaný funkcí print(); __repr__ vrací „vývojářský“ řetězec používaný v REPL a uvnitř výpisů kontejnerů:

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

Výstup:

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

Pokud je definováno pouze __repr__, print() se na něj uchýlí – takže jediné dobře napsané __repr__ obvykle stačí. __str__ definujte také jen tehdy, když má přátelská forma vypadat jinak než vývojářská. Usilujte o __repr__, které vypadá jako volání, jež by objekt znovu vytvořilo; ladění je dramaticky snazší, když jsou vypsané hodnoty jednoznačné.