设计 class 的 Pythonic 方式,它具有可以被 kwargs 覆盖的默认数据成员
Pythonic way to design class which has default data members which can be overridden by kwargs
我认为标题给出了我正在寻找的内容的一般概念,但为了更具体,我将给出一个代码示例。
所以假设我有一个 Python class,其中包含一些必需的位置变量,这些变量也采用任意数量的关键字参数。 class 有很多数据成员,其中一些将由所需的位置变量定义,但大多数是关键字参数变量,程序对这些变量有默认值,但如果用户使用关键字参数,这将覆盖默认值。我正在寻找最“pythonic”的方式来初始化这种类型的 class。关于如何做到这一点,我有两个想法,但每个想法都不令人满意,而且我好像缺少一种更 pythonic 的方式。
#First Option
class SampleOne:
def __init__(pos1, pos2, **kwargs):
def do_defaults():
self.kwarg1 = default_kwarg1
self.kwarg2 = default_kwarg2
self.kwarg3 = default_kwarg3
def do_given():
for variable, value in kwargs.items():
self.variable = value
self.pos1 = pos1
self.pos2 = pos2
do_defaults()
do_given()
或者
#Second Option
class SampleTwo:
def __init__(pos1, pos2, **kwargs):
self.pos1 = pos1
self.pos2 = pos2
self.kwarg1 = kwargs[kwarg1] if kwarg1 in kwargs else default_kwarg1
self.kwarg2 = kwargs[kwarg2] if kwarg2 in kwargs else default_kwarg2
self.kwarg3 = kwargs[kwarg3] if kwarg3 in kwargs else default_kwarg3
我不喜欢第一个选项,因为如果要更改一堆默认数据成员,设置一堆默认数据成员似乎很浪费,尤其是在有很多数据成员的情况下。
我不喜欢第二个选项,因为在我看来它看起来过于繁琐且可读性较差 - 我喜欢将默认值与 user-defined 值分开,并认为这会使我的代码更易于理解阅读和改变。
此外,我正在使用 **kwargs 而不是具有默认值的关键字参数,因为我仍处于此代码库开发的早期阶段,因此所需的成员变量可能会发生变化,但也因为正在进行有很多成员变量,拥有所有这些参数会使函数签名变得非常难看。
抱歉,如果我的问题有点 long-winded,这是我第一次在 Whosebug 上提问,我想确保我提供了足够的细节。
此外,如果它有所不同,我的代码需要在 Python 3.8 及更高版本中工作。
这是一种可能的解决方案:
class Solution:
def __init__(self, pos1, pos2, **kwargs):
self.pos1 = pos1
self.pos2 = pos2
for key, value in kwargs.items():
if key not in self.__dict__:
self.__dict__[key] = value
else:
raise ValueError(f"{key} already exists in Solution")
您需要注意不要覆盖 class 中的方法或现有变量,所以我让它抛出异常以防您尝试这样做。
用法示例:
>>> solution = Solution(1, 2, kwarg1=1, kwarg2=2, kwarg3=3, kwarg4=4)
>>> print(solution.__dict__)
{'pos1': 1, 'pos2': 2, 'kwarg1': 1, 'kwarg2': 2, 'kwarg3': 3, 'kwarg4': 4}
>>> solution.kwarg4
4
指定您要支持的默认值并采用不需要默认值的任意值。这使您的 类 可读并且实现(相对)清晰:
class Sample:
def __init__(
self,
pos1,
pos2,
kwarg1='default_1',
kwarg2='default_2',
kwarg3='default_3',
**kwargs
):
self.pos1 = pos1
self.pos2 = pos2
self.kwarg1 = kwarg1
self.kwarg2 = kwarg2
self.kwarg3 = kwarg3
for k, v in kwargs.items():
setattr(self, k, v)
我认为标题给出了我正在寻找的内容的一般概念,但为了更具体,我将给出一个代码示例。
所以假设我有一个 Python class,其中包含一些必需的位置变量,这些变量也采用任意数量的关键字参数。 class 有很多数据成员,其中一些将由所需的位置变量定义,但大多数是关键字参数变量,程序对这些变量有默认值,但如果用户使用关键字参数,这将覆盖默认值。我正在寻找最“pythonic”的方式来初始化这种类型的 class。关于如何做到这一点,我有两个想法,但每个想法都不令人满意,而且我好像缺少一种更 pythonic 的方式。
#First Option
class SampleOne:
def __init__(pos1, pos2, **kwargs):
def do_defaults():
self.kwarg1 = default_kwarg1
self.kwarg2 = default_kwarg2
self.kwarg3 = default_kwarg3
def do_given():
for variable, value in kwargs.items():
self.variable = value
self.pos1 = pos1
self.pos2 = pos2
do_defaults()
do_given()
或者
#Second Option
class SampleTwo:
def __init__(pos1, pos2, **kwargs):
self.pos1 = pos1
self.pos2 = pos2
self.kwarg1 = kwargs[kwarg1] if kwarg1 in kwargs else default_kwarg1
self.kwarg2 = kwargs[kwarg2] if kwarg2 in kwargs else default_kwarg2
self.kwarg3 = kwargs[kwarg3] if kwarg3 in kwargs else default_kwarg3
我不喜欢第一个选项,因为如果要更改一堆默认数据成员,设置一堆默认数据成员似乎很浪费,尤其是在有很多数据成员的情况下。
我不喜欢第二个选项,因为在我看来它看起来过于繁琐且可读性较差 - 我喜欢将默认值与 user-defined 值分开,并认为这会使我的代码更易于理解阅读和改变。
此外,我正在使用 **kwargs 而不是具有默认值的关键字参数,因为我仍处于此代码库开发的早期阶段,因此所需的成员变量可能会发生变化,但也因为正在进行有很多成员变量,拥有所有这些参数会使函数签名变得非常难看。
抱歉,如果我的问题有点 long-winded,这是我第一次在 Whosebug 上提问,我想确保我提供了足够的细节。
此外,如果它有所不同,我的代码需要在 Python 3.8 及更高版本中工作。
这是一种可能的解决方案:
class Solution:
def __init__(self, pos1, pos2, **kwargs):
self.pos1 = pos1
self.pos2 = pos2
for key, value in kwargs.items():
if key not in self.__dict__:
self.__dict__[key] = value
else:
raise ValueError(f"{key} already exists in Solution")
您需要注意不要覆盖 class 中的方法或现有变量,所以我让它抛出异常以防您尝试这样做。
用法示例:
>>> solution = Solution(1, 2, kwarg1=1, kwarg2=2, kwarg3=3, kwarg4=4)
>>> print(solution.__dict__)
{'pos1': 1, 'pos2': 2, 'kwarg1': 1, 'kwarg2': 2, 'kwarg3': 3, 'kwarg4': 4}
>>> solution.kwarg4
4
指定您要支持的默认值并采用不需要默认值的任意值。这使您的 类 可读并且实现(相对)清晰:
class Sample:
def __init__(
self,
pos1,
pos2,
kwarg1='default_1',
kwarg2='default_2',
kwarg3='default_3',
**kwargs
):
self.pos1 = pos1
self.pos2 = pos2
self.kwarg1 = kwarg1
self.kwarg2 = kwarg2
self.kwarg3 = kwarg3
for k, v in kwargs.items():
setattr(self, k, v)