在不重复代码的情况下检查 class 函数输入是否有效

Checking if class fucntion inputs are valid without duplicating code

我正在尝试创建一个公司 class 并且到目前为止已经编写了以下代码:

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

如您所见,我有这种适合我的验证过程,问题是我想创建更改实例名称、库存编号等的函数' 我希望这些函数输入具有与原始实例输入相同的验证过程。

例如:

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

有什么方法可以不从 __init__ 复制相同的代码吗?或者必须输入所有 valid() 个参数而不是我想要的那个?

您可以将验证检查抽象为它自己的函数,并在整个 class 中调用它。也可以在构造函数中使用,在对象初始化时自动调用

如果您要使用 setter 来检查字段的有效性,那么您只需让构造函数调用 setter。您的所有字段都独立于其他字段,因此您真的不需要主要的有效性检查功能。

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 (
        '  ' not in name and
        isinstance(name, str) and
        name.replace(' ','').isalpha() and
        name[0].isupper() and
        len(name) > 2
    ) 

请注意,所有这些 isinstance 检查都不是真正的 Pythonic。当您强制执行严格类型时,您会阻止调用者使用 duck typing 来传递可以工作但您没有预料到的类型。我会删除它们。

说到 Pythonic,setter 也不是很流行。您可以将它们切换为 properties,以便用户可以使用 =.

分配给字段