如何在Python3类初始化函数中使用**kwargs?

2024-03-29 13:30:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在用Python3编写一个类,我希望能够从用户那里获取各种关键字参数,并存储这些值以供以后在类方法中使用。示例代码如下所示:

class MathematicalModel:
    def __init__(self, var1, var2, var3, **kwargs):
        self.var1 = var1
        self.var2 = var2
        self.var3 = var3
        self.var4 = kwarg1
        self.var5 = kwarg2
        self.var6 = kwarg6

    def calculation1(self):
        x = self.var1 + self.var2 + self.var3
        return x

    def calculation2(self):
        y = self.var1 * self.var2 * var3
        return y

class MathematicalModelExtended(MathematicalModel):
    def __init__(self, var1, var2, var3, **kwargs):
        super.__init__(self, var1, var2, var3, **kwargs)

    def calculation1(self):
        '''Overrides calculation1 method from parent DoThis'''
        x = (self.var1 + self.var2 + self.var3) / self.kwarg1
        return x

    def calculation2(self):
        '''Overrides calculation2 method from parent DoThis'''
        y = (self.var1 * self.var2 * self.var3) / (self.kwarg1 + self.kwarg2)
        return y

a = MathematicalModel(1, 2, 3)
b = MathematicalModelExtended(1, 2, 3, var4 = 4, var5 = 5, var6 = 6)

但是,我不确定这是如何工作的,原因如下: a) 如果用户没有为b、c、甚至a提供参数,该怎么办?然后代码将抛出一个错误,因此我不确定在这种情况下如何初始化这些属性。 b) 当我不知道用户事先传递了什么关键字参数时,如何访问与关键字关联的值

我计划在数学公式中使用变量。某些变量(不包括在kwargs)将在每个公式中使用,而其他变量(在kwargs中的变量)将仅在其他公式中使用。为了实现这一点,我计划将MathematicalModel封装在另一个类中,如so MathematicalModelExtended(MathematicalModel)

谢谢大家!


Tags: 用户self参数returninitdef关键字kwargs
1条回答
网友
1楼 · 发布于 2024-03-29 13:30:53

夸尔格一般思想

使用self.var = value加载变量时,它会将变量添加到可以使用self.__dict__访问的内部字典中

class Foo1:

    def __init__(self, **kwargs):
        self.a = kwargs['a']
        self.b = kwargs['b']

foo1 = Foo1(a=1, b=2)
print(foo1.a)  # 1
print(foo1.b)  # 2
print(foo1.__dict__)  # {'a': 1, 'b': 2}

如果希望允许任意参数,可以利用kwargs也是字典这一事实,并使用update()函数

class Foo2:

    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

foo2 = Foo2(some_random_variable=1, whatever_the_user_supplies=2)
print(foo2.some_random_variable)  # 1
print(foo2.whatever_the_user_supplies)  # 2
print(foo2.__dict__)  # {'some_random_variable': 1, 'whatever_the_user_supplies': 2}

这将防止您在尝试存储不存在的值时出错

class Foo3:

    def __init__(self, **kwargs):
        self.a = kwargs['a']
        self.b = kwargs['b']

foo3 = Foo3(a=1)  # KeyError: 'b'

如果希望确保在类中设置变量ab,而不管用户提供了什么,可以创建类属性或使用kwargs.get()

class Foo4:

    def __init__(self, **kwargs):
        self.a = kwargs.get('a', None)
        self.b = kwargs.get('b', None)

foo4 = Foo4(a=1)
print(foo4.a)  # 1
print(foo4.b)  # None
print(foo4.__dict__)  # {'a': 1, 'b': None}

但是,使用此方法,变量属于类而不是实例。这就是为什么会看到foo5.b返回字符串,但它不在foo5.__dict__

class Foo5:

    a = 'Initial Value for A'
    b = 'Initial Value for B'

    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

foo5 = Foo5(a=1)
print(foo5.a)  # 1
print(foo5.b)  # Initial Value for B
print(foo5.__dict__)  # {'a': 1}

如果您允许用户自由指定他们想要的任何kwargs,则可以在函数中迭代__dict__

class Foo6:

    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

    def do_something(self):
        for k, v in self.__dict__.items():
            print(f"{k} -> {v}")

foo6 = Foo6(some_random_variable=1, whatever_the_user_supplies=2)
foo6.do_something()
# some_random_variable -> 1
# whatever_the_user_supplies -> 2

但是,根据您在类中执行的其他操作,最终可能会得到比用户提供的更多的实例属性。因此,最好让用户提供一个字典作为参数

class Foo7:

    def __init__(self, user_vars):
        self.user_vars  = user_vars

    def do_something(self):
        for k, v in self.user_vars.items():
            print(f"{k} -> {v}")

foo7 = Foo7({'some_random_variable': 1, 'whatever_the_user_supplies': 2})
foo7.do_something()
# some_random_variable -> 1
# whatever_the_user_supplies -> 2

寻址您的代码

对于更新的代码,我建议使用self.__dict__.update(kwargs)方法。然后,您可以在没有遇到所依赖的变量(option1方法)时引发错误,也可以在未定义该变量的情况下为该变量设置默认值(option2方法)

class MathematicalModel:
    def __init__(self, var1, var2, var3, **kwargs):
        self.var1 = var1
        self.var2 = var2
        self.var3 = var3
        self.__dict__.update(kwargs)  # Store all the extra variables


class MathematicalModelExtended(MathematicalModel):
    def __init__(self, var1, var2, var3, **kwargs):
        super().__init__(var1, var2, var3, **kwargs)

    def option1(self):
        # Trap error if you need var4 to be specified
        if 'var4' not in self.__dict__:
            raise ValueError("Please provide value for var4")

        x = (self.var1 + self.var2 + self.var3) / self.var4
        return x

    def option2(self):
        # Use .get() to provide a default value when the user does not provide it.
        _var4 = self.__dict__.get('var4', 1)

        x = (self.var1 + self.var2 + self.var3) / self.var4
        return x


a = MathematicalModel(1, 2, 3)
b = MathematicalModelExtended(1, 2, 3, var4=4, var5=5, var6=6)
print(b.option1())  # 1.5
print(b.option2())  # 1.5

当然,如果MathematicalModel永远不会使用除var1var2var3之外的任何东西,那么传递kwargs是没有意义的

class MathematicalModel:
    def __init__(self, var1, var2, var3, **kwargs):
        self.var1 = var1
        self.var2 = var2
        self.var3 = var3

class MathematicalModelExtended(MathematicalModel):
    def __init__(self, var1, var2, var3, **kwargs):
        super().__init__(var1, var2, var3)
        self.__dict__.update(kwargs)

    def option1(self):
        # Trap error if you need var4 to be specified
        if 'var4' not in self.__dict__:
            raise ValueError("Please provide value for var4")

        x = (self.var1 + self.var2 + self.var3) / self.var4
        return x

    def option2(self):
        # Use .get() to provide a default value when the user does not provide it.
        _var4 = self.__dict__.get('var4', 1)

        x = (self.var1 + self.var2 + self.var3) / self.var4
        return x


a = MathematicalModel(1, 2, 3)
b = MathematicalModelExtended(1, 2, 3, var4=4, var5=5, var6=6)
print(b.option1())  # 1.5
print(b.option2())  # 1.5

相关问题 更多 >