2.21. Métodos e atributos

Um método é uma função definida dentro de uma classe. O primeiro parâmetro é a instância sobre a qual o método é chamado; a convenção é chamá-lo self.

2.21.1. Métodos de instância

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

Resultado:

5.0

A chamada p.magnitude() passa p como self automaticamente. Os corpos dos métodos lêem e actualizam atributos através de self da mesma forma que as funções lêem e actualizam nomes através de parâmetros.

2.21.2. Atributos de instância vs atributos de classe

Os atributos atribuídos a self – tipicamente dentro de __init__ – pertencem a essa instância em particular:

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

a.x e b.x têm armazenamento diferente; alterar um não afecta o outro.

Os nomes atribuídos no corpo da classe, fora de qualquer método, são partilhados por todas as instâncias da classe:

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
A class block at the top holding shared methods and the class attribute "kind"; below it, two instance boxes each holding their own "value" attribute, with arrows from each instance up to the class.

Os atributos de classe vivem na classe e são partilhados. Os atributos de instância vivem em cada instância.

Um atributo de classe é acedido da mesma forma que um atributo de instância (a.kind); o Python procura primeiro na instância e depois na classe. Atribuir a a.kind criaria um novo atributo de instância que sombrearia o atributo de classe, deixando b.kind inalterado.

Use atributos de classe para constantes e valores por omissão que todas as instâncias devem ver da mesma forma. Use atributos de instância para estado do qual cada objecto deve ter a sua própria cópia.

2.21.3. __str__ e __repr__

Dois métodos especiais controlam como uma instância é impressa. __str__ devolve a string «amigável» usada por print(); __repr__ devolve a string de «programador» usada no REPL e dentro de representações de contentores:

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

Resultado:

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

Se apenas __repr__ estiver definido, print() recorre a ele – por isso um único __repr__ bem escrito é geralmente suficiente. Defina __str__ também apenas quando a forma amigável deve parecer diferente da forma de programador. Procure que um __repr__ pareça a chamada que recriaria o objecto; a depuração torna-se dramaticamente mais fácil quando os valores impressos são inequívocos.