【问题标题】:Modify Class Constant in Python在 Python 中修改类常量
【发布时间】:2018-01-24 01:28:32
【问题描述】:

在 Python 中,我定义了一个类:

class X():
    _CON = 0

    def __init__(self, var):
        self.y = var*self._CON 

是否可以为X 的实例更改常量_CON?例如,我尝试执行以下操作

X._CON = 3
x = X(2)
a = x.y 

我希望 _CON 从 0 更改为 3,因此 self.y = var*_CON = 2*3 = 6。除了创建一个新类之外,正确的方法是什么?


编辑

我找到了答案。我的第二个代码有效。但是,它改变的不是xX 的实例_CON,而是X 类本身的X。以下代码更改实例x_CON 而不是类X 的更改。

x = X(2)
x._CON = 3
x.__init__(2)

【问题讨论】:

  • 你能澄清你的问题吗?你的预期结果是什么?你认为a 的值是多少?
  • 如果我按原样执行您的示例,则会收到异常NameError: global name '_CON' is not defined。您需要将其更改为self.y = var * X._CONself.y = var * self._CON,如下@Mateen Ulhaq 所述。
  • 恕我直言,如果您使用minimum complete verifiable example 改进您的问题,您将获得更好的答案
  • @MarkMikofski:我已经编辑了我的问题。现在是不是更清楚了?
  • 是的,它更清晰,但您的示例代码甚至没有运行。你试过了吗?您的问题的答案是肯定的,但您必须更改您的代码示例,如我的 cmets 和下面的投票答案中所示

标签: python class class-constants


【解决方案1】:

不,您不能从实例/对象更新类变量。因为它是设计使然,所以必须对所有对象保持不变。虽然存在一些技巧(创建一个类方法来更新变量或像往常一样使用 init 方法。)..

class MyClass:
    _CON = 1

    @classmethod
    def update(cls, value):
        cls._CON += value

    def __init__(self,value):
        self.value = value
        self.update(value)

a = MyClass(1)
print (MyClass._CON) #o/p: 2

在更新以下划线开头的任何内容之前,您必须思考 10 次(有人说不要碰它...)

【讨论】:

    【解决方案2】:

    是否可以更改 X 实例的常量 _CON。

    不。如果你想要这个,你必须使用像self.con这样的实例变量。

    在您的示例中,_CON 附加到类 X。要将其附加到实例,您必须使用self

    【讨论】:

    • OP 也可以使用 class 名称本身,我的意思是,他可以使用X._CON 而不是self._CON。如果我将 OP 的示例更改为 self.y = var * X._CON,那么我会得到 a = 6
    【解决方案3】:

    _CON 是类级别变量,而不是实例级别变量。如果您在类中更改_CON,那么_CON 的值将针对您的类X 的所有实例而更改。如果_CON 的值不是静态的,那么我会将其作为实例级别变量包含在内,而不是将其定义为类变量。

    【讨论】:

    • 我同意,但请查看我的代码更正和版本问题。
    【解决方案4】:

    其实是这样的。当您分配给实例属性时,您会屏蔽类属性。

    因此,如果您执行C()._CON,您指的是实例命名空间,而如果您执行C._CON,您指的是类名称空间。您可以分配给实例和类属性不被触及。

    c = C()
    c._CON = random()
    

    您可以通过self.__class__._CONtype(self)._CON 从实例访问类命名空间

    这些都没有经过测试。

    注意_CON 没有在X.__init__ 处全局定义,因此您应该在x = X(2) 行收到NameError: global name _CON is not defined 错误。

    还有一个问题,因为你在__init__ 中使用了_CON,所以在实例化之后更改它不会影响y 属性,因为这个值已经被计算过了。在这种情况下,更好的做法是扩展X 类并自定义_CON 属性。

    class Y(X):
        _CON = 3
    y = Y(2)
    

    【讨论】:

    • 我测试了我的代码,稍微修正了 _CON -> self._CON。它按我的意图工作。另请参阅我在问题中的新编辑。
    • 显式调用 init 不是很优雅......但是它可能会起作用。为什么不延长?
    • 我同意明确调用 init 的不优雅。我可能应该使用 init 以外的类方法名。我只是想更改类方法中使用的类常量。扩展类也是一个好主意。
    • 但 OP 明确表示不要创建新类。每次更改 X._CON 时它都会更新的一种方法是使 y 成为 property 并将 var 设置为实例变量,然后 y = property(lambda self: X._CON * self.var) 意味着您可以更改 X._CON 即使在您实例化x = X(2)。很抱歉 lambda 使用不当,但 cmets 不会多行 sn-ps。
    • @MarkMikofski 关于我禁止创建新课程的说法完全正确。财产对我来说是新的。很高兴知道这一点。
    【解决方案5】:

    正如我在this comment 中所说的,我将在这里展开,如果 OP 希望能够即时更改X._CON,即使在实例化x = X(var) 之后并且没有编写新类,那么一种方法可能是使y 成为propertyvar 的实例属性,如下所示:

    class X(object):
        _CON = 0
    
        def __init__(self, var):
            self.var = var
    
        @property
        def y(self):
            return self.var * X._CON
    

    然后...

    >>> x = X(2)
    >>> x.y  # returns 0
    
    >>> X._CON = 3
    >>> x.y  # returns 6
    

    N.B.:正如其他人所指出的,我认为 OP 已经发现,此示例使用类属性 X._CON 并且对类属性的更改将影响该类的所有实例。比如从上面实例化x = X(var)后执行下面的,X._CON的值还是3;它不会是 0。

    请特别注意以下示例中大写X和小写x实例之间的区别:

    >>> x._CON = 23  # <-- doesn't affect x.y b/c x.y = x.var * X._CON
    >>> x.y  # still returns 6 b/c X._CON = 3 still
    
    >>> x10 = X(10)
    >>> x10.y  # returns 30 b/c X._CON = 3
    
    >>> x._CON  # returns 23
    >>> x10._CON  # returns 3 since we changed X._CON to 3
    >>> X._CON  # returns 3 <-- this is the **class** attribute
    

    因此,如果您希望 _CON 的值特定于每个实例,请使用 self._CON 而不是 X._CON。重新开始……

    class X(object):
        _CON = 0
    
        def __init__(self, var):
            self.var = var
    
        @property
        def y(self):
            return self.var * self._CON  # <-- use **instance** attribute
    

    然后...

    >>> x = X(2)
    >>> x.y  # returns 0
    
    >>> x._CON = 3  # <-- use **instance** attribute
    >>> x.y  # returns 6
    
    >>> x10 = X(10)
    >>> x10.y  # returns 0 b/c x10._CON = X._CON = 0
    
    >>> x10._CON = 7  # <-- use **instance** attribute
    >>> x10.y  # returns 70
    
    >>> x._CON  # returns 3
    >>> x10._CON  # returns 7
    >>> X._CON  # returns 0
    

    还有一些变体,例如,如果您在设置实例属性 @ 之前或之后更改类属性 X._CON,则在使用 self._CON 的第二个示例中,实例属性 x._CONx10._CON 会发生什么变化987654344@ 或x10._CON。我会把这些例子留给读者去探索。

    【讨论】:

      猜你喜欢
      • 2021-12-15
      • 2012-11-04
      • 2015-01-30
      • 2011-01-11
      • 2015-01-31
      • 1970-01-01
      • 1970-01-01
      • 2020-02-26
      • 1970-01-01
      相关资源
      最近更新 更多