Attribute mutator generate Typeerror if it does not receive a number

Asked

Viewed 80 times

0

I’m trying to make a phone error treatment where when it’s set some value other than a number it throws a TypeError.

Can someone see if I’m doing it right or where I can adjust?

from typing import Union, List, Dict

Number = Union[int, float]


class Cliente():
    """
    Classe Cliente do Banco.

    possui os atributos PRIVADOS:
    - nome,
    - telefone,
    - email.
    caso o telefone não seja um número inteiro gera um TypeError
    """

    def __init__(self, nome: str, telefone: int, email: str ):
        self.__nome = nome
        self.__telefone = telefone
        self.__email = email


    def get_nome(self) -> str:
        """Acessor do atributo Nome."""
        return self.__nome

    def get_telefone(self) -> int:
        """Acessor do atributo Telefone."""
        return self.__telefone


    def set_telefone(self, novo_telefone: int) -> None:
        """
        Mutador do atributo telefone, caso não receba um número,
        gera um TypeError
        """
        try: 
            novo_telefone == int
        except TypeError:
            print("Erro: Digite apenas números inteiros")
        else:
            self.__telefone = novo_telefone
            return self.__telefone

Pytest sempre esta retornando string


def test_set_telefone_erro():
    c = Cliente('nome', 99999999, '[email protected]')
    try:
        c.set_telefone('não é telefone')
    except TypeError:
        assert True
    except Exception:
        assert False, 'Não lançou um TypeError para telefone inválido'
    else:
        assert c.get_telefone() == 99999999

1 answer

1

In doing novo_telefone == int you are comparing the value of the new phone with the class itself int (and will never be equal). To know the type of the variable, one option is to use isinstance:

def set_telefone(self, novo_telefone: int) -> None:
    if not isinstance(novo_telefone, int):
        raise TypeError(f"{novo_telefone!r} não é um número inteiro")
    self.__telefone = novo_telefone

That is, if the new phone is int, changes. Otherwise, it launches a TypeError (I followed the comment of your code that says "if you do not receive a number, generates a Typeerror"). Note that the method throws the exception in case of invalid data. But you were trying to capture the exception, which in the case was not generated, so never fell into the except.

I also took the return, because it doesn’t make much sense Setter return the value that has just been set (in addition to being consistent with the hinttype, indicating that the function returns None).

Example of use:

c = Cliente('nome', 99999999, '[email protected]')
try:
    c.set_telefone('não é telefone')
except TypeError as e:
    print('Número de telefone não foi alterado:', e)

print(c.get_telefone()) # 99999999

This code prints out:

Número de telefone não foi alterado: 'não é telefone' não é um número inteiro
99999999

Another detail is that you are not taking advantage of the same validation logic in the constructor. That is, in your class you can create a client with an invalid phone:

Cliente('nome', 'abc', '[email protected]')

An alternative for the same logic to be repurposed is by using properties:

class Cliente:
    def __init__(self, nome: str, telefone: int, email: str ):
        self._nome = nome
        self.telefone = telefone
        self._email = email

    @property
    def telefone(self) -> int:
        return self._telefone

    @telefone.setter
    def telefone(self, novo_telefone: int) -> None:
        if not isinstance(novo_telefone, int):
            raise TypeError(f"{novo_telefone!r} não é um número inteiro")
        self._telefone = novo_telefone

c = Cliente('nome', 99999999, '[email protected]')
try:
    c.telefone = 'não é telefone'
except TypeError as e:
    print('Número de telefone não foi alterado:', e)

Thus the TypeError is also launched when trying to create a client with an invalid phone (ie, Cliente('nome', 'abc', '[email protected]') also launches the exception).

I didn’t create the properties for the name and email, but based on the code above, it will not be difficult to do so.

To learn more about property, see here (this link also gives a great explanation for not using field names starting with two _ - note the code above that I changed to use only one _).


That being said, phones are not whole numbers. They are information that happens to use digits, which is quite different.

For example, if I treat the data as numbers, then 80012345678 and 080012345678 are the same number: both represent the same numerical value, since the zero on the left makes no difference (and indeed, if you try to use set_telefone(0800), will give error because 0800 is not a valid numeric literal).

But 80012345678 and 080012345678 are completely different phones. The zeroes on the left make a difference (try dialing an 0800 service without putting zero in front and it won’t work). There are also cases of telephones with letters (not so common in Brazil, but in other countries yes), IDD codes usually have the + in front (+5511999991234), etc. So the phone should be a string, not a number.

Browser other questions tagged

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