Properties no Python 2.6
Uma das features que eu mais gosto em Python são as properties. Elas são possíveis graças aos descriptors, mas isso é assunto pra outro post. E na versão 2.6, as properties ganharam 3 atributos: getter, setter e deleter. Veja mais aqui
Primeiro, vou mostrar como elas sempre funcionaram. Ai vai um exemplo “dummy”, não levem em conta a funcionalidade em si (sou péssimo em exemplos):
class Conta(object):
def __init__(self, saldo = 0.0):
self.saldo = saldo
def depositar(self, valor):
if valor > 0:
self.saldo += valor
return True
return False
Certo, uma classe Conta, onde eu posso depositar um valor, que incrementa meu ‘saldo’. Mas como ver o saldo? Os “Javeiros” de plantão perguntariam logo: “Onde está o getter do saldo?!”. E eu respondo: “Não tem :-)”. Simplesmente porque não precisa. Se você quiser ver o saldo, acesse o atributo direto:
>>> c = Conta(100.00)
>>> print c.saldo
100.00
>>> c.depositar(20.00)
>>> print c.saldo
120.00
Mas isso não fere o encapsulamento? Um dos princípios básico da OO!?! É aí que entra as properties. Em Python, atributos são acessados diretamente, só se você precisar fazer algo quando acessá-lo, ai você cria um getter, e transforma o atributo numa property. Vejamos como ficaria a classe Conta:
from datetime import datetime
class Conta(object):
def __init__(self, saldo = 0.0):
self._saldo = saldo
self._ultimo_acesso = None
def depositar(self, valor):
if valor > 0:
self._saldo += valor
return True
return False
def _get_saldo(self):
self._ultimo_acesso = datetime.now()
return self._saldo
saldo = property(_get_saldo)
Agora, ao acessar a ‘property’ saldo, estaremos chamando o método _get_saldo()
. O cliente da classe continua com a mesma API. Veja que eu usei um underline (_) na frente dos atributos, isso em Python é uma convenção, pra informar que o atributo é “privado”, já que não existem atributos realmente privados.
>>> c = Conta(100.00)
>>> print c.saldo
100.00
>>> print c._ultimo_acesso
2008-12-28 14:30:05.598644
Ou seja, getters e setters? Somente quando precisar. Confesso que depois de conhecer essa feature, dá dor na vista ler códigos em Java, PHP, etc…com vários getX, getY, getZ somente com uma linha retornando o atributo equivalente.
Uma property é um descriptor que conecta funções ao acesso a um determinado atributo. Tem a seguinte assinatura:
property(fget=None, fset=None, fdel=None, doc=None)
Vamos criar um setter para a classe acima:
def _set_saldo(self, novo_saldo):
if novo_saldo > 0:
self._saldo = novo_saldo
# a property agora seria
saldo = property(_get_saldo, _set_saldo)
Aqui vai o código na íntegra, com alguns doctests: conta.py.
Sim, mas o que mudou no Python 2.6? Veja como eu poderia criar o getter e setter:
@property
def saldo(self):
self._ultimo_acesso = datetime.now()
return self._saldo
@saldo.setter
def saldo(self, novo_saldo):
if novo_saldo > 0:
self._saldo = novo_saldo
Aqui está o código moficado: conta2.py.
Referências: