【问题标题】:Python: Should I use a Constant or a Property?Python:我应该使用常量还是属性?
【发布时间】:2013-06-19 00:45:08
【问题描述】:

以下两种方法中的哪一种被认为是最佳做法?两者都达到了相同的结果。

class Foo():
    LABELS = ('One','Two','Three')

class Bar():
    def __init__(self):
        self.__labels = ('One','Two','Three')

    @property
    def labels(self):
        return self.__labels

【问题讨论】:

    标签: python syntax constants


    【解决方案1】:

    如果您不需要自定义获取或设置行为,则将某些内容设为属性是没有意义的。第一个版本更好。

    此外,它们的行为并不完全相同。在Foo 中,标签有一个类级别的属性。在Bar 中,没有。引用Foo.LABELS 可以正常工作,引用Bar.labels 会抛出异常。

    【讨论】:

      【解决方案2】:

      第一个变体传达,标签在类的所有实例上声明,...

      class Foo():
          LABELS = ('One','Two','Three')
      

      而第二个看起来标签是特殊的,例如。如果标签不变,我会选择第一个 - 它更连贯。

      【讨论】:

      • 实际上,它们并没有在实例上声明。这些是静态变量。尝试在实例上查找 LABELS 在内部失败,但在查找类时成功。例如:ideone.com/qfWlbe
      【解决方案3】:

      PEP 8 Style Guide for Python Code 提供第三种方式,Zen of Python 同意。

      他们建议添加一个非常简单的模块,创建一个命名空间来定义常量。

      整个内容例如package/constants.py:

      LABELS = ('One', 'Two', 'Three')
      

      示例用法:

      from package.constants import LABELS
      print(LABELS)  # -> ('One', 'Two', 'Three')
      

      请注意,这里没有任何明确的常量“保护”。您可以跳过箍以尝试获得恒定的常数...或者您可以接受您设置的任何保护措施都可以被真正想要的人避开,然后只需重新引用有关同意成年人的内容的人,然后遵循一个非常明智的概念,即 ALL_CAPS 中的变量得到足够多的开发人员的适当尊重,您不必担心强制执行您的常量概念。

      【讨论】:

        【解决方案4】:

        这取决于变量使用的范围。我使用类变量作为对常量的引用,很像 C 中的#define SOMETHING。另一方面,实例变量对于不同的实例可能具有不同的值。也许一个例子会更好地解释这一点。

        class ChessBoardTile:
            BLACK = 'black'
            WHITE = 'white'
            def __init__(self,clr):
                self._color = clr
        
        t = ChessBoardTile(ChessBoardTile.BLACK)
        

        【讨论】:

          【解决方案5】:

          我做了一个例子试图说服你采用第二种方法,但我很困惑......

          >>> class Foo():
          ...     LABELS = ('One','Two','Three')
          ... 
          >>> Foo.LABELS
          ('One', 'Two', 'Three')
          >>> Foo.LABELS = (1,2,3)
          >>> Foo.LABELS
          (1, 2, 3)
          >>> f = Foo()
          >>> g = Foo()
          >>> f.LABELS = ('a','b','c')
          >>> g.LABELS
          (1, 2, 3)
          >>> Foo.LABELS
          (1, 2, 3)
          >>> f.LABELS
          ('a', 'b', 'c')
          

          “发生了什么事?”我心想。然后我意识到行为取决于对象ID......

          >>> id(Foo.LABELS)
          4562309280
          >>> id(g.LABELS)
          4562309280
          >>> id(f.LABELS)
          4562068336
          >>> ('a','b','c') is ('a','b','c')
          False
          >>> Foo.LABELS = (4,5,6)
          >>> g.LABELS
          (4, 5, 6)
          >>> f.LABELS
          ('a', 'b', 'c')
          >>> id(Foo.LABELS)
          4562309200
          >>> id(g.LABELS)
          4562309200
          >>> id(f.LABELS)
          4562068336
          

          所以,回到我原来的答案:除非你不在乎你的变量是否被重新分配,否则不要采用第一种方法,因为你得到的不是你所期望的。第一种方法使变量属于类,第二种方法使变量属于实例 - 但如果有人在第一种情况下重新分配变量,你会得到一些非常奇怪的结果。

          推论 - 如果你的类方法只引用类的变量(即Foo.LABELS),那么你显然会得到你所期望的,但如果有人以不同的方式重用你的代码,那么谁知道他们是什么会得到吗?

          推论 #2 - 在 python 中没有办法强制引用不变性。所以你真的应该采用第二种方法。

          【讨论】:

          • 这实际上是一个属性在哪里分配的问题,而不是与属性有关的问题。如果您想要属性的独立实例级值,请在 __init__ 方法中分配它,而不是将其留在类中。通常,这对于任何可能发生变化的事物都是一个好主意。但最好给它分配常量值 - 只需在 __init__ 中设置 LABELS = ('One', 'Two', 'Three')
          【解决方案6】:

          肯定是第一个,因为:

          • 更简单,更能传达您的意图

          • 它可能使用更少的内存,因为它是类变量只评估一次。而第二个示例一遍又一遍地创建相同的元组,它可能不会被缓存(内部化)。

          • 正如其他人指出的那样,您可以要求 Foo.LABELS 可能用于向常量添加结构。

          【讨论】:

          猜你喜欢
          • 2016-01-10
          • 2017-10-09
          • 2022-08-16
          • 1970-01-01
          • 1970-01-01
          • 2012-05-06
          • 2021-11-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多