Introdução
Esta seção discute alguns decoradores (decorators) embutidos que são usados em combinação com definições de métodos.
This tutorial is from open-source community. Access the source code
Esta seção discute alguns decoradores (decorators) embutidos que são usados em combinação com definições de métodos.
Existem decoradores (decorators) predefinidos usados para especificar tipos especiais de métodos em definições de classe.
class Foo:
def bar(self,a):
...
@staticmethod
def spam(a):
...
@classmethod
def grok(cls,a):
...
@property
def name(self):
...
Vamos analisar cada um deles.
@staticmethod é usado para definir os chamados métodos de classe estáticos (do C++/Java). Um método estático é uma função que faz parte da classe, mas que não opera em instâncias.
class Foo(object):
@staticmethod
def bar(x):
print('x =', x)
>>> Foo.bar(2) ## x=2
>>>
Métodos estáticos são, por vezes, usados para implementar código de suporte interno para uma classe. Por exemplo, código para ajudar a gerenciar instâncias criadas (gerenciamento de memória, recursos do sistema, persistência, bloqueio, etc.). Eles também são usados por certos padrões de projeto (não discutidos aqui).
@classmethod é usado para definir métodos de classe. Um método de classe é um método que recebe o objeto classe como o primeiro parâmetro, em vez da instância.
class Foo:
def bar(self):
print(self)
@classmethod
def spam(cls):
print(cls)
>>> f = Foo()
>>> f.bar()
<__main__.Foo object at 0x971690> ## The instance `f`
>>> Foo.spam()
<class '__main__.Foo'> ## The class `Foo`
>>>
Métodos de classe são frequentemente usados como uma ferramenta para definir construtores alternativos.
class Date:
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
@classmethod
def today(cls):
## Notice how the class is passed as an argument
tm = time.localtime()
## And used to create a new instance
return cls(tm.tm_year, tm.tm_mon, tm.tm_mday)
d = Date.today()
Métodos de classe resolvem alguns problemas complexos com recursos como herança.
class Date:
...
@classmethod
def today(cls):
## Gets the correct class (e.g. `NewDate`)
tm = time.localtime()
return cls(tm.tm_year, tm.tm_mon, tm.tm_mday)
class NewDate(Date):
...
d = NewDate.today()
Nos seus arquivos report.py e portfolio.py, a criação de um objeto Portfolio é um pouco confusa. Por exemplo, o programa report.py tem um código como este:
def read_portfolio(filename, **opts):
'''
Read a stock portfolio file into a list of dictionaries with keys
name, shares, and price.
'''
with open(filename) as lines:
portdicts = fileparse.parse_csv(lines,
select=['name','shares','price'],
types=[str,int,float],
**opts)
portfolio = [ Stock(**d) for d in portdicts ]
return Portfolio(portfolio)
e o arquivo portfolio.py define Portfolio() com um inicializador estranho como este:
class Portfolio:
def __init__(self, holdings):
self._holdings = holdings
...
Francamente, a cadeia de responsabilidade é um pouco confusa porque o código está disperso. Se uma classe Portfolio deve conter uma lista de instâncias Stock, talvez você devesse mudar a classe para ser um pouco mais clara. Assim:
## portfolio.py
import stock
class Portfolio:
def __init__(self):
self._holdings = []
def append(self, holding):
if not isinstance(holding, stock.Stock):
raise TypeError('Expected a Stock instance')
self._holdings.append(holding)
...
Se você quiser ler um portfólio de um arquivo CSV, talvez devesse criar um método de classe para isso:
## portfolio.py
import fileparse
import stock
class Portfolio:
def __init__(self):
self._holdings = []
def append(self, holding):
if not isinstance(holding, stock.Stock):
raise TypeError('Expected a Stock instance')
self._holdings.append(holding)
@classmethod
def from_csv(cls, lines, **opts):
self = cls()
portdicts = fileparse.parse_csv(lines,
select=['name','shares','price'],
types=[str,int,float],
**opts)
for d in portdicts:
self.append(stock.Stock(**d))
return self
Para usar esta nova classe Portfolio, você pode agora escrever um código como este:
>>> from portfolio import Portfolio
>>> with open('portfolio.csv') as lines:
... port = Portfolio.from_csv(lines)
...
>>>
Faça estas alterações na classe Portfolio e modifique o código report.py para usar o método de classe.
Parabéns! Você completou o laboratório de Métodos Decorados. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.