Home > Software design >  Checking if class fucntion inputs are valid without duplicating code
Checking if class fucntion inputs are valid without duplicating code

Time:02-26

I'm trying to create a Company class and so far have written this code:

class Company:
   
    def __init__(self, name, stocks_num, stock_price, comp_type):
        self.name = name
        self.stocks_num = stocks_num
        self.stock_price = stock_price
        self.comp_type = comp_type
        if not self.valid(name,stocks_num, stock_price, comp_type):
            raise ValueError("wrong Company Input")

    def valid(self,name,stocks_num,stock_price,comp_type):
        valid = True
        check_list = [name, comp_type]
        while check_list:
            if '  ' in check_list[0] or not isinstance(check_list[0], str) or not check_list[0].replace(' ','').isalpha() or not check_list[0][0].isupper()  \
                    or not len(check_list[0]) > 2:
                valid = False
            check_list.pop(0)

        if not isinstance(stocks_num, int) or not stocks_num > 0:
            valid = False

        if not isinstance(stock_price, int) and not isinstance(stock_price, float) or not stock_price > 0:
            valid = False

        return valid

and as you can see I have this kind of validation process that works well for me, the problem is I want to create functions that change the instances' name, stock num, etc' and I want these function inputs to have the same validation process the original instance input had.

for example:

def set_name(self, name):
    # change company name
   *checks if only the name is valid* 
    self.name = valid_new_name

Is there any way to do it without duplicating the same code from the __init__? or having to input all the valid() arguments instead of just the one I want?

CodePudding user response:

You can abstract your validation check into its own function and call it throughout the class. It can also be used in the constructor and it will be called automatically when an object is initialized

CodePudding user response:

If you're going to have setters that check the fields' validity then you can simply have the constructor call the setters. All of your fields are independent from the others so you don't really need a master validity check function.

class Company:
    def __init__(self, name, stocks_num, stock_price, comp_type):
        self.set_name(name)
        self.set_stocks_num(stocks_num)
        self.set_stock_price(stock_price)
        self.set_comp_type(comp_type)

    def set_name(self, name):
        if not is_valid_name(name):
            raise ValueError("bad name")
        self.name = name

    def set_stocks_num(self, stocks_num):
        if not isinstance(stocks_num, int) or not stocks_num > 0:
            raise ValueError("bad stocks_num")
        self.stocks_num = stocks_num

    def set_stock_price(self, stock_price):
        if not isinstance(stock_price, int) and not isinstance(stock_price, float) or not stock_price > 0:
            raise ValueError("bad stock_price")
        self.stock_price = stock_price

    def set_comp_type(self, comp_type):
        if not is_valid_name(comp_type):
            raise ValueError("bad comp_type")
        self.comp_type = comp_type

def is_valid_name(name):
    return (
        '  ' in name and
        isinstance(name, str) and
        name.replace(' ','').isalpha() and
        name[0].isupper() and
        len(name) > 2
    ) 

Note that all these isinstance checks are not really Pythonic. When you enforce strict typing you block callers from using duck typing to pass in types that would work but you didn't anticipate. I would delete them.

Speaking of Pythonic, setters aren't really in fashion either. You could switch these to properties so users can assign to the fields using =.

  • Related