How to allow only the creation of valid objects in Python?

Asked

Viewed 54 times

1

class Linha(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    @property
    def x(self):
        return self._x
    @x.setter
    def x(self, valor):
        if valor >= 0:
            self._x = valor
    @property
    def y(self):
        return self._y
    @y.setter
    def y(self, valor):
        if valor >= 0:
            self._y = valor

I created this class that basically abstracted a line, realize that I made use of decorators setters so that do not allow entry of value less than 0.

But when I try to create an instance of Line if I pass one of the parameters as less than 0 it still makes the creation of the object but does not create this attribute.

Example:

linha = Linha(-1, 1)

If I do this it will create the object but it will not have the attribute x because it will not be set. If worse still if I pass the two negative attributes the object will be created but will not have any attribute.

My question is this: how do I avoid creating an invalid object? That is, if one or more invalid parameters are passed, the object is not created.

  • 1

    I believe that this is the case to make an exception, instead of transparently ignoring the attribution of the attribute. By the way, you’ve abstracted a point in the first quadrant, not exactly a line. You can even generate a line from this information, but in this case you would be being misleading.

1 answer

2


As Jefferson commented in the question, you can make an exception when the set number is invalid, in this case, less than zero. The exception will divert the flow of the program by delegating the treatment logic of the error for a higher layer, the program that creates the class instance.

class Linha(object):

    def __init__(self, x, y):
        self.x = x
        self.y = y

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, valor):
        if valor >= 0:
            self._x = valor
        else:
            raise ValueError("The x value must be a non-negative number")

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, valor):
        if valor >= 0:
            self._y = valor
        else:
            raise ValueError("The y value must be a non-negative number")

Another detail that is possibly valid to do in this situation, since within the methods you compare the value with an integer, is to ensure that this comparison is possible by ensuring that the value is also numerical. I mean, if I did obj.x = 'a', would give an error saying that the operator >= does not support a comparison between a string and an integer. This is a bad error message to deliver to your client (who uses the class). To get around this, you can convert the input value to integer (or float), before making the comparison:

class Linha(object):

    def __init__(self, x, y):
        self.x = x
        self.y = y

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, valor):
        valor_inteiro = int(valor)
        if valor_inteiro >= 0:
            self._x = valor_inteiro
        else:
            raise ValueError("The x value must be a non-negative number")

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, valor):
        valor_inteiro = int(valor)
        if valor_inteiro >= 0:
            self._y = valor_inteiro
        else:
            raise ValueError("The y value must be a non-negative number")

So if I try to create the instance Linha('a', 0), the error message will be:

Valueerror: invalid literal for int() with base 10: 'a'

Which is much clearer about what is wrong with the code and even makes the method always throw the same exception, ValueError, in both possible cases, which facilitates treatment in the upper layer.

try:
    x = input("Valor de x:")
    y = input("Valor de y:")
    linha = Linha(x, y)
except ValueError as error:
    print(error)

Browser other questions tagged

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