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
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.