我正在用Python创建一个类,并且不确定如何正确设置默认值。我的目标是为所有类实例设置默认值,也可以通过类方法对其进行修改。但是,我想在调用方法后恢复初始默认值。
我已经能够使其与下面显示的代码一起使用。它不是很“漂亮”,所以我怀疑这是解决此问题的更好方法。
class plots:
def __init__(self, **kwargs):
self.default_attr = {'a': 1, 'b': 2, 'c': 3}
self.default_attr.update(kwargs)
self.__dict__.update((k, v) for k, v in self.default_attr.items())
def method1(self, **kwargs):
self.__dict__.update((k, v) for k, v in kwargs.items())
#### Code for this method goes here
# Then restore initial default values
self.__dict__.update((k, v) for k, v in self.default_attr.items())
使用此类时,我会做类似my_instance = plots()
和my_instance.method1()
,my_instance.method1(b = 5)
和my_instance.method1()
的事情。第三次调用method1
时,如果我不重设方法定义末尾的默认值,b
将为5,但我希望再次为2。
注意:上面的代码仅是示例。实型类具有数十个默认值,将所有默认值用作输入参数将被视为反模式。
关于如何正确解决此问题的任何建议?
答案 0 :(得分:1)
您可以使用类变量和属性来实现为所有类实例设置默认值的目标。实例值可以直接修改,调用方法后可以恢复初始默认值。
鉴于“真实类具有数十个默认值”,您可能会考虑的另一种方法是设置包含默认值的配置文件,并使用该文件初始化或重置默认值。
以下是使用一个类变量的第一种方法的简短示例:
class Plots:
_a = 1
def __init__(self):
self._a = None
self.reset_default_values()
def reset_default_values(self):
self._a = Plots._a
@property
def a(self):
return self._a
@a.setter
def a(self, value):
self._a = value
plot = Plots()
print(plot.a)
plot.a = 42
print(plot.a)
plot.reset_default_values()
print(plot.a)
输出:
1
42
1
答案 1 :(得分:0)
您可以使用上下文管理器或装饰器来应用和重置值,而不必在每种方法上键入相同的代码。
我没有回到self.default_attr
,而是回到了先前的状态。
使用装饰器,您可以获得:
def with_kwargs(fn):
def inner(self, **kwargs):
prev = self.__dict__.copy()
try:
self.__dict__.update(kwargs)
ret = fn(self)
finally:
self.__dict__ = prev
return ret
return inner
class plots:
a = 1
b = 2
c = 3
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
@with_kwargs
def method1(self):
# Code goes here
恕我直言,这是一个坏主意,至少会建议不要更改plots
。您可以通过创建一个新对象并将其作为method1
传递给self
来实现。
class Transparent:
pass
def with_kwargs(fn):
def inner(self, **kwargs):
new_self = Transparent()
new_self.__dict__ = {**self.__dict__, **kwargs}
return fn(new_self)
return inner
答案 2 :(得分:0)
有很多方法可以解决此问题,但是如果您安装了python 3.7(或安装了the backport并安装了python 3.7),dataclasses可能是一个不错的解决方案的好选择。
首先,它允许您以可读和紧凑的方式定义默认值,还允许您需要的所有变异操作:
>>> from dataclasses import dataclass
>>> @dataclass
... class Plots:
... a: int = 1
... b: int = 2
... c: int = 3
...
>>> p = Plots() # create a Plot with only default values
>>> p
Plots(a=1, b=2, c=3)
>>> p.a = -1 # update something in this Plot instance
>>> p
Plots(a=-1, b=2, c=3)
您还可以选择使用dataclass field definition免费定义默认工厂而不是默认值。也许这还不是问题,但是它避免了mutable default value gotcha,每个Python程序员迟早都会碰到它。
最后但并非最不重要的一点是,在已有数据类的情况下,编写reset
函数非常容易,因为它可以跟踪其__dataclass_fields__
属性中已经存在的所有默认值:
>>> from dataclasses import dataclass, MISSING
>>> @dataclass
... class Plots:
... a: int = 1
... b: int = 2
... c: int = 3
...
... def reset(self):
... for name, field in self.__dataclass_fields__.items():
... if field.default != MISSING:
... setattr(self, name, field.default)
... else:
... setattr(self, name, field.default_factory())
...
>>> p = Plots(a=-1) # create a Plot with some non-default values
>>> p
Plots(a=-1, b=2, c=3)
>>> p.reset() # calling reset on it restores the pre-defined defaults
>>> p
Plots(a=1, b=2, c=3)
因此,现在您可以编写一些函数do_stuff(...)
来更新Plot实例中的字段,并且只要执行reset()
,更改就不会持久。