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 =
.