【问题标题】:python temporary change of class defaultpython临时更改类默认值
【发布时间】:2018-02-22 14:00:45
【问题描述】:

我想临时更改一个类的默认值。我想出了一些想法:

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)。有什么进一步的想法或改进吗?

提前致谢

【问题讨论】:

  • 为什么不简单地在创建这个类的实例时设置你想要的值呢?
  • 看起来这对工厂来说更有意义。
  • @Haleemur 我需要创建大量实例。所以变体1非常重复。
  • @khelwood :好主意,不过,我需要多次更改默认值。因此,我最终会创建 100 家工厂,或者再次通过一个论点,这将使创建工厂变得多余甚至更加混乱。
  • 拥有数百家工厂不会花费您任何成本。

标签: python default temporary


【解决方案1】:

这是我的建议,涉及工厂。

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()

c1c2c3value[1,2,3]
c4c5c6value[100,12]

如果您将其他参数传递给 C 初始化程序,您可以将参数添加到 make_cfactory 和/或 lambda 函数。

【讨论】:

    【解决方案2】:

    有一个可选的关键字参数是在 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
    

    【讨论】:

    • 感谢您指出可变性问题。不过,您的答案是我的方法 1 - 在消除可变性问题时。
    • 我认为方法 1 是最 Pythonic 的。但是,如果它不适合您,请随时等待另一个。
    • @Daniel Böckenhoff 我也为您的其他方法添加了一种解决可变性问题的方法
    猜你喜欢
    • 2021-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多