python 临时更改 class 默认值
python temporary change of class default
我想临时更改 class 的默认值。我想到了一些想法:
class C(object):
VALUE_DEFAULT = [1, 2, 3]
def __init__(self, value=None):
if value is None:
value = self.VALUE_DEFAULT
self._value = value
@property
def value(self):
return self._value
print("Initial default:", C().value)
"""
1) Repetitious version that makes code unclear if multiple
instances should be instantiated or the default should not be used.
"""
print("Changed default manually:", C(value=[0, 2, 4]).value)
"""
2) dangerously hard coded version
"""
C.VALUE_DEFAULT = [0, 2, 4]
print("Changed default by changing the default constant:", C().value)
C.VALUE_DEFAULT = [1, 2, 3]
"""
3) possibly more pythonic version
still this version seems hacky
"""
from contextlib import contextmanager
@contextmanager
def tmp_default(cls, name, value):
old_val = getattr(cls, name)
setattr(cls, name, value)
yield
setattr(cls, name, old_val)
with tmp_default(C, "VALUE_DEFAULT", [0, 2, 4]):
print("Changed default with contextmanager:", C().value)
print("Restored the default again:", C().value)
从上面的可能性来看,我非常喜欢 3)。有什么进一步的想法或改进吗?
提前致谢
在 Python 中应该采用具有可选关键字参数的方式。不过,我想指出您的代码存在的问题。
class C(object):
VALUE_DEFAULT = [1, 2, 3]
def __init__(self, value=None):
if value is None:
value = self.VALUE_DEFAULT
self._value = value
@property
def value(self):
return self._value
c1 = C()
c2 = C()
c1.value [0] = 10
c2.value # [10, 2, 3]
由于您将相同的可变列表分配为默认值,因此更新 c1.value
会更新 C.VALUE_DEFAULT
.
这是解决此问题的方法。
class C(object):
def __init__(self, value=None):
# create a new array everytime
self._value = [1, 2, 3] if value is None else value
@property
def value(self):
return self._value
只要您需要默认值以外的值,就可以将其作为关键字提供 value
。
或者,如果您想解决可变性错误,但仍使用其他解决方案,则需要 copy
。
import copy
class C(object):
VALUE_DEFAULT = [1, 2, 3]
def __init__(self, value=None):
if value is None:
value = copy.copy(self.VALUE_DEFAULT)
self._value = value
@property
def value(self):
return self._value
这是我的建议,涉及工厂。
def make_cfactory(argument):
return lambda : C(argument.copy())
我想用参数 [1,2,3]
实例化一堆 C
,但我不想继续输入 [1,2,3]
。我没有使用 C(...)
实例化它们,而是使用工厂实例化它们。
cfac = make_cfactory([1,2,3])
c1 = cfac()
c2 = cfac()
c3 = cfac()
cfac = make_cfactory([100,12])
c4 = cfac()
c5 = cfac()
c6 = cfac()
c1
、c2
和 c3
有 value
个 [1,2,3]
。
c4
、c5
和 c6
有 value
个 [100,12]
。
如果您将其他参数传递给 C
初始化程序,您可以将 make_cfactory
and/or 的参数添加到 lambda 函数。
我想临时更改 class 的默认值。我想到了一些想法:
class C(object):
VALUE_DEFAULT = [1, 2, 3]
def __init__(self, value=None):
if value is None:
value = self.VALUE_DEFAULT
self._value = value
@property
def value(self):
return self._value
print("Initial default:", C().value)
"""
1) Repetitious version that makes code unclear if multiple
instances should be instantiated or the default should not be used.
"""
print("Changed default manually:", C(value=[0, 2, 4]).value)
"""
2) dangerously hard coded version
"""
C.VALUE_DEFAULT = [0, 2, 4]
print("Changed default by changing the default constant:", C().value)
C.VALUE_DEFAULT = [1, 2, 3]
"""
3) possibly more pythonic version
still this version seems hacky
"""
from contextlib import contextmanager
@contextmanager
def tmp_default(cls, name, value):
old_val = getattr(cls, name)
setattr(cls, name, value)
yield
setattr(cls, name, old_val)
with tmp_default(C, "VALUE_DEFAULT", [0, 2, 4]):
print("Changed default with contextmanager:", C().value)
print("Restored the default again:", C().value)
从上面的可能性来看,我非常喜欢 3)。有什么进一步的想法或改进吗?
提前致谢
在 Python 中应该采用具有可选关键字参数的方式。不过,我想指出您的代码存在的问题。
class C(object):
VALUE_DEFAULT = [1, 2, 3]
def __init__(self, value=None):
if value is None:
value = self.VALUE_DEFAULT
self._value = value
@property
def value(self):
return self._value
c1 = C()
c2 = C()
c1.value [0] = 10
c2.value # [10, 2, 3]
由于您将相同的可变列表分配为默认值,因此更新 c1.value
会更新 C.VALUE_DEFAULT
.
这是解决此问题的方法。
class C(object):
def __init__(self, value=None):
# create a new array everytime
self._value = [1, 2, 3] if value is None else value
@property
def value(self):
return self._value
只要您需要默认值以外的值,就可以将其作为关键字提供 value
。
或者,如果您想解决可变性错误,但仍使用其他解决方案,则需要 copy
。
import copy
class C(object):
VALUE_DEFAULT = [1, 2, 3]
def __init__(self, value=None):
if value is None:
value = copy.copy(self.VALUE_DEFAULT)
self._value = value
@property
def value(self):
return self._value
这是我的建议,涉及工厂。
def make_cfactory(argument):
return lambda : C(argument.copy())
我想用参数 [1,2,3]
实例化一堆 C
,但我不想继续输入 [1,2,3]
。我没有使用 C(...)
实例化它们,而是使用工厂实例化它们。
cfac = make_cfactory([1,2,3])
c1 = cfac()
c2 = cfac()
c3 = cfac()
cfac = make_cfactory([100,12])
c4 = cfac()
c5 = cfac()
c6 = cfac()
c1
、c2
和 c3
有 value
个 [1,2,3]
。
c4
、c5
和 c6
有 value
个 [100,12]
。
如果您将其他参数传递给 C
初始化程序,您可以将 make_cfactory
and/or 的参数添加到 lambda 函数。