Introdução
Várias partes do comportamento do Python podem ser personalizadas através de métodos especiais ou os chamados métodos "mágicos" (magic methods). Esta seção introduz essa ideia. Além disso, o acesso dinâmico a atributos e métodos vinculados (bound methods) são discutidos.
Introdução
Classes podem definir métodos especiais. Estes têm um significado especial para o interpretador Python. Eles são sempre precedidos e seguidos por __. Por exemplo, __init__.
class Stock(object):
def __init__(self):
...
def __repr__(self):
...
Existem dezenas de métodos especiais, mas analisaremos apenas alguns exemplos específicos.
Métodos Especiais para Conversões de String
Objetos têm duas representações de string.
>>> from datetime import date
>>> d = date(2012, 12, 21)
>>> print(d)
2012-12-21
>>> d
datetime.date(2012, 12, 21)
>>>
A função str() é usada para criar uma saída imprimível agradável:
>>> str(d)
'2012-12-21'
>>>
A função repr() é usada para criar uma representação mais detalhada para programadores.
>>> repr(d)
'datetime.date(2012, 12, 21)'
>>>
Essas funções, str() e repr(), usam um par de métodos especiais na classe para produzir a string a ser exibida.
class Date(object):
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
## Used with `str()`
def __str__(self):
return f'{self.year}-{self.month}-{self.day}'
## Used with `repr()`
def __repr__(self):
return f'Date({self.year},{self.month},{self.day})'
Nota: A convenção para __repr__() é retornar uma string que, quando fornecida a eval(), recriará o objeto subjacente. Se isso não for possível, algum tipo de representação facilmente legível é usado em vez disso.
Métodos Especiais para Matemática
Operadores matemáticos envolvem chamadas aos seguintes métodos.
a + b a.__add__(b)
a - b a.__sub__(b)
a * b a.__mul__(b)
a / b a.__truediv__(b)
a // b a.__floordiv__(b)
a % b a.__mod__(b)
a << b a.__lshift__(b)
a >> b a.__rshift__(b)
a & b a.__and__(b)
a | b a.__or__(b)
a ^ b a.__xor__(b)
a ** b a.__pow__(b)
-a a.__neg__()
~a a.__invert__()
abs(a) a.__abs__()
Métodos Especiais para Acesso a Itens
Estes são os métodos para implementar containers.
len(x) x.__len__()
x[a] x.__getitem__(a)
x[a] = v x.__setitem__(a,v)
del x[a] x.__delitem__(a)
Você pode usá-los em suas classes.
class Sequence:
def __len__(self):
...
def __getitem__(self,a):
...
def __setitem__(self,a,v):
...
def __delitem__(self,a):
...
Invocação de Método
Invocar um método é um processo de duas etapas.
- Lookup (Pesquisa): O operador
. - Chamada de método: O operador
()
>>> s = stock.Stock('GOOG',100,490.10)
>>> c = s.cost ## Lookup
>>> c
<bound method Stock.cost of <Stock object at 0x590d0>>
>>> c() ## Method call
49010.0
>>>
Métodos Vinculados (Bound Methods)
Um método que ainda não foi invocado pelo operador de chamada de função () é conhecido como um método vinculado (bound method). Ele opera na instância onde se originou.
>>> s = stock.Stock('GOOG', 100, 490.10)
>>> s
<Stock object at 0x590d0>
>>> c = s.cost
>>> c
<bound method Stock.cost of <Stock object at 0x590d0>>
>>> c()
49010.0
>>>
Métodos vinculados são frequentemente uma fonte de erros descuidados e não óbvios. Por exemplo:
>>> s = stock.Stock('GOOG', 100, 490.10)
>>> print('Cost : %0.2f' % s.cost)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: float argument required
>>>
Ou um comportamento traiçoeiro que é difícil de depurar.
f = open(filename, 'w')
...
f.close ## Oops, Didn't do anything at all. `f` still open.
Em ambos os casos, o erro é causado por esquecer de incluir os parênteses finais. Por exemplo, s.cost() ou f.close().
Acesso a Atributos
Existe uma forma alternativa de acessar, manipular e gerenciar atributos.
getattr(obj, 'name') ## Same as obj.name
setattr(obj, 'name', value) ## Same as obj.name = value
delattr(obj, 'name') ## Same as del obj.name
hasattr(obj, 'name') ## Tests if attribute exists
Exemplo:
if hasattr(obj, 'x'):
x = getattr(obj, 'x'):
else:
x = None
*Nota: getattr() também possui um valor padrão útil *arg*.
x = getattr(obj, 'x', None)
Exercício 4.9: Melhor saída para impressão de objetos
Modifique o objeto Stock que você definiu em stock.py para que o método __repr__() produza uma saída mais útil. Por exemplo:
>>> goog = stock.Stock('GOOG', 100, 490.1)
>>> goog
Stock('GOOG', 100, 490.1)
>>>
Veja o que acontece quando você lê um portfólio de ações e visualiza a lista resultante após fazer essas alterações. Por exemplo:
>>> import report
>>> portfolio = report.read_portfolio('portfolio.csv')
>>> portfolio
... see what the output is ...
>>>
Exercício 4.10: Um exemplo de uso de getattr()
getattr() é um mecanismo alternativo para ler atributos. Ele pode ser usado para escrever código extremamente flexível. Para começar, experimente este exemplo:
>>> import stock
>>> s = stock.Stock('GOOG', 100, 490.1)
>>> columns = ['name', 'shares']
>>> for colname in columns:
print(colname, '=', getattr(s, colname))
name = GOOG
shares = 100
>>>
Observe cuidadosamente que os dados de saída são determinados inteiramente pelos nomes dos atributos listados na variável columns.
No arquivo tableformat.py, use essa ideia e expanda-a em uma função generalizada print_table() que imprime uma tabela mostrando atributos especificados pelo usuário de uma lista de objetos arbitrários. Assim como com a função print_report() anterior, print_table() também deve aceitar uma instância de TableFormatter para controlar o formato de saída. Veja como deve funcionar:
>>> import report
>>> portfolio = report.read_portfolio('portfolio.csv')
>>> from tableformat import create_formatter, print_table
>>> formatter = create_formatter('txt')
>>> print_table(portfolio, ['name','shares'], formatter)
name shares
---------- ----------
AA 100
IBM 50
CAT 150
MSFT 200
GE 95
MSFT 50
IBM 100
>>> print_table(portfolio, ['name','shares','price'], formatter)
name shares price
---------- ---------- ----------
AA 100 32.2
IBM 50 91.1
CAT 150 83.44
MSFT 200 51.23
GE 95 40.37
MSFT 50 65.1
IBM 100 70.44
>>>
Resumo
Parabéns! Você concluiu o laboratório de Métodos Especiais. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.