如何在Python中声明常量?
在Java中,我们做:
public static final String CONST_NAME = "Name";
如何在Python中声明常量?
在Java中,我们做:
public static final String CONST_NAME = "Name";
当前回答
在python中,常量只是一个变量,名称全大写,单词之间用下划线分隔,
e.g
Days_in_week = 7
该值是可变的,即您可以更改它。但既然名字的规则告诉你是常数,你为什么要这么做呢?我是说,这毕竟是你的项目!
这是python中采用的方法。出于同样的原因,没有private关键字。用下划线作为名称的前缀,您就知道它是私有的。代码可以打破规则....就像程序员可以删除private关键字一样。
Python可以添加一个const关键字…但是程序员可以删除关键字,然后如果他们想要更改常量,但为什么要这样做呢?如果你想打破规则,你可以改变规则。但如果名字的意思已经很清楚了,为什么还要费心打破规则呢?
也许在某些单元测试中,对值应用更改是有意义的?看看一周8天会发生什么,尽管在现实世界中,一周的天数是不能改变的。如果语言阻止你做一个例外,如果只有这一个情况,你需要打破规则……然后您将不得不停止将它声明为常量,即使它在应用程序中仍然是常量,并且只有这个测试用例来查看如果它被更改会发生什么。
全大写的名称告诉您它是一个常量。这才是重要的。没有一种语言强制约束代码,无论如何你都可以修改。
这就是python的哲学。
其他回答
扩展Raufio的答案,添加__repr__来返回值。
class const(object):
def __init__(self, val):
super(const, self).__setattr__("value", val)
def __setattr__(self, name, val):
raise ValueError("Trying to change a constant value", self)
def __repr__(self):
return ('{0}'.format(self.value))
dt = const(float(0.01))
print dt
那么对象的行为就更像你所期望的那样,你可以直接访问它而不是使用"。value "
编辑:添加了Python 3的示例代码
注意:另一个答案看起来提供了一个更完整的实现,类似于下面(具有更多的功能)。
首先,创建一个元类:
class MetaConst(type):
def __getattr__(cls, key):
return cls[key]
def __setattr__(cls, key, value):
raise TypeError
这可以防止静态属性被更改。然后创建另一个使用该元类的类:
class Const(object):
__metaclass__ = MetaConst
def __getattr__(self, name):
return self[name]
def __setattr__(self, name, value):
raise TypeError
或者,如果你使用的是python3:
class Const(object, metaclass=MetaConst):
def __getattr__(self, name):
return self[name]
def __setattr__(self, name, value):
raise TypeError
这应该可以防止实例道具被更改。要使用它,继承:
class MyConst(Const):
A = 1
B = 2
现在,直接或通过实例访问的props应该是常量:
MyConst.A
# 1
my_const = MyConst()
my_const.A
# 1
MyConst.A = 'changed'
# TypeError
my_const.A = 'changed'
# TypeError
下面是上面的一个例子。下面是Python 3的另一个例子。
在Python中,常量是不存在的,但是你可以通过在变量名的开头添加CONST_并在注释中声明它是一个常量来表明变量是一个常量并且不能被改变:
myVariable = 0
CONST_daysInWeek = 7 # This is a constant - do not change its value.
CONSTANT_daysInMonth = 30 # This is also a constant - do not change this value.
或者,你可以创建一个像常量一样的函数:
def CONST_daysInWeek():
return 7;
你可以使用StringVar或IntVar等,你的常量是const_val
val = 'Stackoverflow'
const_val = StringVar(val)
const.trace('w', reverse)
def reverse(*args):
const_val.set(val)
我知道这是一个老问题,但由于新的解决方案仍在添加,我想使可能的解决方案列表更加完整。你可以通过从类中继承属性来实现实例中的常量,如下所示:
class ConstantError(Exception):
pass # maybe give nice error message
class AllowConstants:
_constants = None
_class_constants = None
def __init__(self):
self._constants = {}
if self._class_constants is not None:
self._constants.update(self._class_constants)
def constant(self, name, value):
assert isinstance(name, str)
assert self._constants is not None, "AllowConstants was not initialized"
if name in self._constants or name in self.__dict__:
raise ConstantError(name)
self._constants[name] = value
def __getattr__(self, attr):
if attr in self._constants:
return self._constants[attr]
raise AttributeError(attr)
def __setattr__(self, attr, val):
if self._constants is None:
# not finished initialization
self.__dict__[attr] = val
else:
if attr in self._constants:
raise ConstantError(attr)
else:
self.__dict__[attr] = val
def __dir__(self):
return super().__dir__() + list(self._constants.keys())
子类化this时,你创建的常量将受到保护:
class Example(AllowConstants):
def __init__(self, a, b):
super().__init__()
self.constant("b", b)
self.a = a
def try_a(self, value):
self.a = value
def try_b(self, value):
self.b = value
def __str__(self):
return str({"a": self.a, "b": self.b})
def __repr__(self):
return self.__str__()
example = Example(1, 2)
print(example) # {'a': 1, 'b': 2}
example.try_a(5)
print(example) # {'a': 5, 'b': 2}
example.try_b(6) # ConstantError: b
example.a = 7
print(example) # {'a': 7, 'b': 2}
example.b = 8 # ConstantError: b
print(hasattr(example, "b")) # True
# To show that constants really do immediately become constant:
class AnotherExample(AllowConstants):
def __init__(self):
super().__init__()
self.constant("a", 2)
print(self.a)
self.a=3
AnotherExample() # 2 ConstantError: a
# finally, for class constants:
class YetAnotherExample(Example):
_class_constants = {
'BLA': 3
}
def __init__(self, a, b):
super().__init__(a,b)
def try_BLA(self, value):
self.BLA = value
ex3 = YetAnotherExample(10, 20)
ex3.BLA # 3
ex3.try_BLA(10) # ConstantError: BLA
ex3.BLA = 4 # ConstantError: BLA
常量是局部的(从AllowConstants继承的类的每个实例都有自己的常量),只要它们没有被重新赋值,就像普通的属性一样,并且编写从这个继承的类允许或多或少与支持常量的语言相同的风格。
此外,如果您想通过直接访问实例来防止任何人更改值。_constants,您可以使用其他答案中建议的许多不允许这样做的容器之一。最后,如果你真的觉得有必要,你可以阻止人们设置所有的实例。通过AllowConstants的更多属性访问,将_constants赋给一个新字典。(当然,这些都不是非常python化的,但这不是重点)。
编辑(因为使python非python化是一个有趣的游戏):为了使继承更容易一点,你可以修改AllowConstants如下:
class AllowConstants:
_constants = None
_class_constants = None
def __init__(self):
self._constants = {}
self._update_class_constants()
def __init_subclass__(cls):
"""
Without this, it is necessary to set _class_constants in any subclass of any class that has class constants
"""
if cls._class_constants is not None:
#prevent trouble where _class_constants is not overwritten
possible_cases = cls.__mro__[1:-1] #0 will have cls and -1 will have object
for case in possible_cases:
if cls._class_constants is case._class_constants:
cls._class_constants = None
break
def _update_class_constants(self):
"""
Help with the inheritance of class constants
"""
for superclass in self.__class__.__mro__:
if hasattr(superclass, "_class_constants"):
sccc = superclass._class_constants
if sccc is not None:
for key in sccc:
if key in self._constants:
raise ConstantError(key)
self._constants.update(sccc)
def constant(self, name, value):
assert isinstance(name, str)
assert self._constants is not None, "AllowConstants was not initialized"
if name in self._constants or name in self.__dict__:
raise ConstantError(name)
self._constants[name] = value
def __getattr__(self, attr):
if attr in self._constants:
return self._constants[attr]
raise AttributeError(attr)
def __setattr__(self, attr, val):
if self._constants is None:
# not finished initialization
self.__dict__[attr] = val
else:
if attr in self._constants:
raise ConstantError(attr)
else:
self.__dict__[attr] = val
def __dir__(self):
return super().__dir__() + list(self._constants.keys())
这样你就可以:
class Example(AllowConstants):
_class_constants = {
"BLA": 2
}
def __init__(self, a, b):
super().__init__()
self.constant("b", b)
self.a = a
def try_a(self, value):
self.a = value
def try_b(self, value):
self.b = value
def __str__(self):
return str({"a": self.a, "b": self.b})
def __repr__(self):
return self.__str__()
class ChildExample1(Example):
_class_constants = {
"BLI": 88
}
class ChildExample2(Example):
_class_constants = {
"BLA": 44
}
example = ChildExample1(2,3)
print(example.BLA) # 2
example.BLA = 8 # ConstantError BLA
print(example.BLI) # 88
example.BLI = 8 # ConstantError BLI
example = ChildExample2(2,3) # ConstantError BLA