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