Criando getters e setters no modo “pythonico”. (#dev #python #oop)
Overview
Se você já se perguntou sobre como melhorar o controle de suas classes em Python, este post é para você! Aqui, vamos mergulhar em um exemplo divertido, mas altamente informativo, sobre como implementar getters e setters. Com uma abordagem passo a passo, exploraremos a criação de uma classe ‘User’ para demonstrar como podemos administrar o acesso e as modificações de suas propriedades. Preparado para aprender e, quem sabe, modificar alguns dos seus próprios códigos após isso? Vem comigo!
Neste post mostro um exemplo de como criar getters e setters de forma que você possa criar fluxos mais complexos. O exemplo que utilizo vai ser uma classe que te informa se ela foi modificada ou nao desde que foi criada.
A classe que vou utilizar chama-se User e possui as seguintes propriedades: Name, Login, Password, Email e uma “propriedade privada” chamada “is_modified”.
Veja o código:
class User(object):
def __init__(self, name: str, login: str, password: str, email: str):
self.name = name
self.login = login
self.password = password
self.email = email
self.__is_modified__ = False
def is_modified(self):
return self.__is_modified__
Bom, esta é uma classe normal. Nada demais nela. O que vamos fazer agora é adicionar 2 métodos para cada uma das propriedades (exceto a __is_modified__, ela nao deve ser acessada de fora da classe).
Começando pela propriedade name, vamos fazer o getter:
@property
def name(self):
return self.__name
O getter é composto pelo decorator @property (nativo do python, nao precisa instalar pacotes extras), o método com o mesmo nome da propriedade que queremos criar o getter e o setter. (no caso, name). Este método apenas retorna uma propriedade chamada __name. Todavia, este nome é arbitrário, você pode colocar o nome que desejar, mas repetir o nome da propriedade, incluindo os indicadores de que ela é privada, costuma a ser uma boa ideia.
Agora vamos fazer o setter da propriedade name:
@name.setter
def name(self, value):
if value is None:
raise ValueError("Name cannot be none!")
self.__is_modified__ = True
self.__name = value
O decorator do setter é o nome do método getter, chamando o setter (@name.setter). Este método recebe um argumento, que é o novo valor da propriedade.
Você nao precisa, mas eu coloquei uma validação ali. O nome não pode ser nulo. Então, se a pessoa tentar passar uma string nula como o nome, será lançada uma exception. Também mudei o valor da propriedade __is_modified__ para True e depois fiz o que o setter deveria fazer: definir o valor da propriedade Name.
Assim como no setter, a propriedade interna nao precisa se chamar __name, mas elas tem que ter o mesmo nome entre si, ou seja, o que você usar no setter, tem que usar no getter.
A apliquei a mesma lógica as outras propriedades da classe:
class User(object):
def __init__(self, name: str, login: str, password: str, email: str):
self.name = name
self.login = login
self.password = password
self.email = email
self.__is_modified__ = False
def is_modified(self):
return self.__is_modified__
@property
def name(self):
return self.__name
@name.setter
def name(self, value):
if value is None:
raise ValueError("Name cannot be none!")
self.__is_modified__ = True
self.__name = value
@property
def login(self):
return self.__login
@login.setter
def login(self, value):
if value is None:
raise ValueError("Login cannot be none!")
self.__is_modified__ = True
self.__login = value
@property
def password(self):
return self.__password
@password.setter
def password(self, value):
if value is None:
raise ValueError("Password cannot be none!")
self.__is_modified__ = True
self.__password = value
@property
def email(self):
return self.__email
@email.setter
def email(self, value):
if value is None:
raise ValueError("Email cannot be none!")
self.__is_modified__ = True
self.__email = value
Obviamente, a classe ficou bem maior, mas agora temos o controle sobre o que é devolvido e definido em cada propriedade da classe. No caso, garanti que nenhuma das propriedades dela serão nulas.
Agora para testar o método que detecta se o objeto foi modificado:
if __name__ == '__main__':
user = User(name="John User", login="j.user", email="j.user@gmail.com", password="p4ssw0rd!")
print(f"Created an User. Is it modified? {user.is_modified()}")
user.name = "Updated name"
print(f"Changed an User. Is it modified? {user.is_modified()}")
Exemplo de saída:
Created an User. Is it modified? False
Changed an User. Is it modified? True
Coloquei este exemplo no meu Github.
Espero ter ajudado!