2.21. Metode și atribute

O metodă este o funcție definită în interiorul unei clase. Primul parametru este instanța pe care este apelată metoda; convenția este să-l numești self.

2.21.1. Metode de instanță

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

Ieșire:

5.0

Apelul p.magnitude() transmite automat p drept self. Corpurile metodelor citesc și actualizează atribute prin self în același mod în care funcțiile citesc și actualizează nume prin parametri.

2.21.2. Atribute de instanță vs. de clasă

Atributele atribuite lui self – de obicei în interiorul lui __init__ – aparțin acelei singure instanțe:

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

a.x și b.x reprezintă stocări diferite; modificarea uneia nu o afectează pe cealaltă.

Numele atribuite în corpul clasei, în afara oricărei metode, sunt partajate de fiecare instanță a clasei:

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
Un bloc de clasă în partea de sus care conține metodele partajate și atributul de clasă „kind”; sub el, două cutii de instanță, fiecare deținând propriul atribut „value”, cu săgeți de la fiecare instanță în sus către clasă.

Atributele de clasă trăiesc pe clasa însăși și sunt partajate. Atributele de instanță trăiesc pe fiecare instanță.

Un atribut de clasă este accesat în același mod ca unul de instanță (a.kind); Python caută mai întâi pe instanță, apoi pe clasă. Atribuirea lui a.kind ar crea un nou atribut de instanță care îl umbrește pe cel de clasă, lăsând b.kind neatins.

Folosește atribute de clasă pentru constante și valori implicite pe care fiecare instanță ar trebui să le vadă în același mod. Folosește atribute de instanță pentru starea de care fiecare obiect ar trebui să dețină propria copie.

2.21.3. __str__ și __repr__

Două metode speciale controlează modul în care se afișează o instanță. __str__ returnează șirul „prietenos” folosit de print(); __repr__ returnează șirul „pentru dezvoltatori” folosit la REPL și în afișările de containere:

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

Ieșire:

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

Dacă este definit doar __repr__, print() recurge la el – așa că un singur __repr__ bine scris este de obicei suficient. Definește și __str__ doar atunci când forma prietenoasă ar trebui să arate diferit de forma pentru dezvoltatori. Țintește un __repr__ care arată ca apelul ce ar recrea obiectul; depanarea devine dramatic mai ușoară atunci când valorile afișate sunt lipsite de ambiguitate.