Properties no Python 2.6

28 Dez 2008

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:

Comentários

Gilson Mohr

Bom post
dá uma olhada nesse que não consegui entender....

http://www.flett.org/2005/04/26/cool-python-tricks/

flw

blog comments powered by Disqus