2.21. Metódusok és attribútumok

A metódus egy osztályon belül definiált függvény. Az első paraméter az a példány, amelyen a metódust meghívják; a konvenció szerint self a neve.

2.21.1. Példánymetódusok

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

Kimenet:

5.0

A p.magnitude() hívás automatikusan átadja a p objektumot self paraméterként. A metódustörzsek a self objektumon keresztül olvassák és frissítik az attribútumokat, ugyanúgy, ahogy a függvények a paramétereken keresztül olvassák és frissítik a neveket.

2.21.2. Példány- kontra osztályattribútumok

A self objektumhoz rendelt attribútumok – jellemzően az __init__ metóduson belül – ahhoz az egy példányhoz tartoznak:

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

Az a.x és a b.x különböző tárhely; az egyik módosítása nem érinti a másikat.

Az osztálytörzsben, bármely metóduson kívül rendelt nevek a osztály minden példányán osztoznak:

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
Felül egy osztályblokk, amely a megosztott metódusokat és a "kind" osztályattribútumot tartalmazza; alatta két példánydoboz, mindegyik a saját "value" attribútumával, minden példánytól nyilakkal felfelé az osztály felé.

Az osztályattribútumok magán az osztályon élnek, és megosztottak. A példányattribútumok minden példányon élnek.

Egy osztályattribútumot ugyanúgy érhetsz el, mint egy példányattribútumot (a.kind); a Python először a példányon keres, majd az osztályon. Az a.kind értékadása egy új példányattribútumot hozna létre, amely elfedi az osztályattribútumot, miközben a b.kind érintetlen marad.

Az osztályattribútumokat olyan állandókhoz és alapértelmezésekhez használd, amelyeket minden példánynak ugyanúgy kell látnia. A példányattribútumokat olyan állapothoz, amelyből minden objektumnak a sajátját kell birtokolnia.

2.21.3. __str__ és __repr__

Két speciális metódus szabályozza, hogyan íródik ki egy példány. A __str__ a print() által használt „barátságos” karakterláncot adja vissza; a __repr__ a REPL-ben és a tárolók megjelenítésében használt „fejlesztői” karakterláncot adja vissza:

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

Kimenet:

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

Ha csak a __repr__ van definiálva, a print() arra esik vissza – így egyetlen jól megírt __repr__ általában elegendő. A __str__ metódust csak akkor definiáld emellett, ha a barátságos formának másképp kell kinéznie, mint a fejlesztői formának. Törekedj egy olyan __repr__ metódusra, amely úgy néz ki, mint az a hívás, amely újra létrehozná az objektumot; a hibakeresés drámaian könnyebbé válik, amikor a kiírt értékek egyértelműek.