Validation in the constructor - Python

Asked

Viewed 249 times

0

I made this class however, when I enter values that in theory should not be allowed it continues running normally, even having created a function that makes the validation.

I can’t get it inside the builder.

How to validate this data or call the function before the methods I call for the objects are executed.

class Data():

def __init__(self, dia = 1, mes = 1, ano = 1980):
    self.__dia = dia
    self.__mes = mes
    self.__ano = ano

def eAnterior(self, dataComp):
    if dataComp.getAno() > self.getAno():
        return False
    elif dataComp.getAno() == self.getAno() and dataComp.getMes() > self.getMes():
        return False
    elif dataComp.getAno() == self.getAno() and dataComp.getMes() == self.getMes() and dataComp.getDia() >= self.getDia():
        return False
    else:
        return True

def ePosterior(self, dataComp):
    if dataComp.getAno() < self.getAno():
        return False
    elif dataComp.getAno() == self.getAno() and dataComp.getMes() < self.getMes():
        return False
    elif dataComp.getAno() == self.getAno() and dataComp.getMes() == self.getMes() and dataComp.getDia() <= self.getDia():
        return False
    else:
        return True

def eSimultaneo(self, dataComp):
    if dataComp.getAno() != self.getAno():
        return False
    elif dataComp.getAno() == self.getAno() and dataComp.getMes() != self.getMes():
        return False
    elif dataComp.getAno() == self.getAno() and dataComp.getMes() == self.getMes() and dataComp.getDia() != self.getDia():
        return False
    else:
        return True    

def _valida(self, dia = 0, mes = 0, ano = 0):
    if dia < 1 or dia > 31:
        return False
    elif mes < 1 or mes > 12:
        return False
    elif ano < 1: 
        return False
    return True

def setData(self, dia, mes, ano):
    if self._valida(dia, mes, ano):
        self.setDia(dia)
        self.setMes(mes)
        self.setAno(ano)
    else:
        self.setDia(1)
        self.setMes(1)
        self.setAno(1980)

def __str__(self):
    return f'{self.getDia()}/{self.getMes()}/{self.getAno()}'

def getDia(self):
    return self.__dia

def setDia(self, dia):
    self.__dia = dia

def getMes(self):
    return self.__mes

def setMes(self, mes):
    self.__mes = mes

def getAno(self):
    return self.__ano

def setAno(self, ano):
    self.__ano = ano

if __name__ == '__main__':
data = Data('a', 'b', 'c')
print(data)
data2 = Data(27, 9, 1998)
data3 = Data(27, 9, 2015)
if data.eSimultaneo(data3):
    print('iguais')
else:
    print('diferentes')  
  • In Python we do not use getters and setters. If we need to apply a business rule in these operations we use the property (@property). Knows?

  • I know, but I still could not use the right way. I mean, I can not use =/

  • There is a reason to create a class and not use the datetime.date?

  • yes, academic purposes. @Pedrovonhertwig

1 answer

4


You need to call the validation method within __init__, for example:

class Data():
    def __init__(self, dia = 1, mes = 1, ano = 1980):
        self.__dia = dia 
        self.__mes = mes 
        self.__ano = ano
        if not self._valida():
            raise ValueError("valores inválidos")

It would also be more Pythonic to use the instance attributes in the method _valida, instead of passing arguments whose value the instance already has:

def _valida(self): 
    if not 1 <= self.__dia <= 31:
        return False 
    if not 1 <= self.__mes <= 12:
        return False 
    if self.__ano < 1: 
        return False
    return True

Another tip: as commented, Python does not use getters and setters, but the decorator @property, for example:

@property  # equivale ao getter
def dia(self):
    return self.__dia

@dia.setter  # equivale ao setter
def dia(self, dia):
    self.__dia = dia
    self._valida()  # validando valores novamente

This supports the Pythonic syntax to use minha_instancia.dia as getter and minha_instancia.dia = novo_dia like Setter.

  • Thank you very much! Clarified many doubts.

  • Using the @Property decorator, is it better to use the "_private" or "_protected" attribute? There is a convention about this?

  • 1

    As you may already know, in Python all attributes and methods of a class are public - using _ for protected and __ for private is just conventions that suggest to whom to read the code that a certain attribute should not be accessed directly. In your case, I believe the most appropriate use is to protect the attributes dia, mes and ano, since you interact with them indirectly through the @property. But ultimately it’s a stylistic issue.

  • Buddy, when you call valida() on @dia.Setter, it will return false, without a condition as it will check this and prevent entry of that value into the attribute?

  • 1

    You’re right, ideally you’d have to take the false value and do something with it (like raise an error, as I did in the init method). I didn’t care much about the logic of your program itself, the code was more a demonstration of how it is possible to make an arbitrary function run when someone redefines an attribute like syntax minha_instancia.attr = valor.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.