Python:我应该使用常量还是属性?
以下哪两种方法被视为最佳实践?两者的效果相同Python:我应该使用常量还是属性?,python,syntax,constants,Python,Syntax,Constants,以下哪两种方法被视为最佳实践?两者的效果相同 class Foo(): LABELS = ('One','Two','Three') class Bar(): def __init__(self): self.__labels = ('One','Two','Three') @property def labels(self): return self.__labels 如果您不需要自定义获取或设置行为,那么将某些内容设置为属
class Foo():
LABELS = ('One','Two','Three')
class Bar():
def __init__(self):
self.__labels = ('One','Two','Three')
@property
def labels(self):
return self.__labels
如果您不需要自定义获取或设置行为,那么将某些内容设置为属性是没有意义的。第一个版本更好
class ChessBoardTile:
BLACK = 'black'
WHITE = 'white'
def __init__(self,clr):
self._color = clr
t = ChessBoardTile(ChessBoardTile.BLACK)
而且,它们的行为并不完全相同。在
Foo
中,标签有一个类级属性。在栏中
,没有。引用Foo.LABELS
将正常工作,引用Bar.LABELS
将引发异常。第一个变量表示在类的所有实例上声明标签
class Foo():
LABELS = ('One','Two','Three')
而第二个看起来像是每个实例的标签都是特殊的。如果标签是常量,我会选择第一个,它更连贯。这取决于变量使用的范围。我使用类变量作为常量的引用,很像C中的
#define SOMETHING
。另一方面,实例变量对于不同的实例可能有不同的值。也许一个例子可以更好地解释这一点
class ChessBoardTile:
BLACK = 'black'
WHITE = 'white'
def __init__(self,clr):
self._color = clr
t = ChessBoardTile(ChessBoardTile.BLACK)
我举了一个例子试图说服你采取第二种方法,但我感到困惑
>>> 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中没有强制引用不变性的方法。所以你真的应该选择第二种方法。肯定是第一种,因为:
- 它更简单,更好地传达您的意图
- 它可能使用更少的内存,因为它是只计算一次的类变量。而第二个示例一遍又一遍地创建相同的元组,它可能不会被缓存(内部化)
- 正如其他人所指出的,您可以请求Foo.label,它可能用于向常量添加结构
- 提供了第三种方式,并且得到了客户的同意
他们建议添加一个非常简单的模块,创建一个名称空间来定义常量
整个内容,例如包/常量.py:
LABELS = ('One', 'Two', 'Three')
用法示例:
from package.constants import LABELS
print(LABELS) # -> ('One', 'Two', 'Three')
注意,这里没有任何明确的常量“保护”。你可以通过跳环来获得常数。。。或者你可以接受,你所采取的任何保护措施都可能被真正想保护你的人忽视,然后,只要重新引用那些关于成年人同意的内容,并遵循一个非常明智的概念,即
所有的_CAPS
中的变量都受到足够多的开发人员的适当尊重,您就不必担心强制执行常量的概念。这实际上是一个属性分配到哪里的问题,而不是分配到哪里的问题与属性无关。如果希望属性具有独立的实例级值,请在\uuuu init\uuuu
方法中分配它,而不是将其留在类中。通常,这对于任何可能发生变化的事情都是个好主意。但最好将其赋值为常量-只需在\uuuu init\uuuuu
中设置标签=('1'、'2'、'3')
。为了便于参考,实际上,它们不会在实例上声明。这些是静态变量。尝试在实例上查找标签
在内部失败,但在类上查找时成功。例如: