How do I create a constant in Python?
有没有一种方法可以在python中声明常量?在Java中,我们可以以这种方式创建常量值:
1 | public static final String CONST_NAME ="Name"; |
与Python中的Java常量声明等价的是什么?
不,没有。不能在python中将变量或值声明为常量。只是不要改变它。
如果你在一个班级里,相当于:
1 2 | class Foo(object): CONST_NAME ="Name" |
如果不是,那只是
1 | CONST_NAME ="Name" |
但您可能想看看AlexMartelli在python中的代码片段常量。
在其他语言中没有
下面是一个使用类属性的替代实现:
请注意,对于一个对常量感到好奇的读者来说,这段代码并不容易。见下文解释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | def constant(f): def fset(self, value): raise TypeError def fget(self): return f() return property(fget, fset) class _Const(object): @constant def FOO(): return 0xBAADFACE @constant def BAR(): return 0xDEADBEEF CONST = _Const() print CONST.FOO ##3131964110 CONST.FOO = 0 ##Traceback (most recent call last): ## ... ## CONST.FOO = 0 ##TypeError: None |
代码说明:
还有一些更传统的方式:
(代码相当复杂,下面有更多解释)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class _Const(object): @apply def FOO(): def fset(self, value): raise TypeError def fget(self): return 0xBAADFACE return property(**locals()) CONST = _Const() print CONST.FOO ##3131964110 CONST.FOO = 0 ##Traceback (most recent call last): ## ... ## CONST.FOO = 0 ##TypeError: None |
请注意,@apply decorator似乎已被弃用。
在python中,人们使用命名约定,如
因此,以同样的方式,您可以简单地将常量声明为所有caps,例如
1 | MY_CONSTANT ="one" |
如果您希望这个常量永远不会改变,您可以钩住属性访问并做一些技巧,但是更简单的方法是声明一个函数
1 2 | def MY_CONSTANT(): return"one" |
唯一的问题是,在任何地方,您都必须执行my_constant(),但同样,
还可以使用NamedDuple创建常量:
1 2 3 4 5 6 7 8 9 | >>> from collections import namedtuple >>> Constants = namedtuple('Constants', ['pi', 'e']) >>> constants = Constants(3.14, 2.718) >>> constants.pi 3.14 >>> constants.pi = 3 Traceback (most recent call last): File"<stdin>", line 1, in <module> AttributeError: can't set attribute |
我最近发现了一个非常简洁的更新,它自动产生有意义的错误消息,并阻止通过
1 2 3 4 5 6 7 8 9 10 11 12 13 | class CONST(object): __slots__ = () FOO = 1234 CONST = CONST() # ---------- print(CONST.FOO) # 1234 CONST.FOO = 4321 # AttributeError: 'CONST' object attribute 'FOO' is read-only CONST.__dict__['FOO'] = 4321 # AttributeError: 'CONST' object has no attribute '__dict__' CONST.BAR = 5678 # AttributeError: 'CONST' object has no attribute 'BAR' |
我们将自己定义为使自己成为一个实例,然后使用槽来确保不能添加其他属性。这还删除了
编辑-原始解决方案
我可能错过了一个技巧,但这似乎对我有用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class CONST(object): FOO = 1234 def __setattr__(self, *_): pass CONST = CONST() #---------- print CONST.FOO # 1234 CONST.FOO = 4321 CONST.BAR = 5678 print CONST.FOO # Still 1234! print CONST.BAR # Oops AttributeError |
创建实例允许magic
对于一个价值来说,这是一种痛苦,但是你可以在你的
正如您可能已经知道的,python没有常量:(
也许最简单的选择是为它定义一个函数。例如。
1 2 | def MY_CONSTANT(): return 42 |
除了两个最重要的答案(只使用大写名称的变量,或使用属性使值只读)之外,我还想提到,可以使用元类来实现命名常量。我在GitHub提供了一个使用元类的非常简单的解决方案,如果您希望这些值的类型/名称更具信息性,这可能会有所帮助:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | >>> from named_constants import Constants >>> class Colors(Constants): ... black = 0 ... red = 1 ... white = 15 ... >>> c = Colors.black >>> c == 0 True >>> c Colors.black >>> c.name() 'black' >>> Colors(0) is c True |
这是稍微高级一点的python,但仍然非常容易使用和方便。(该模块还有一些其他功能,包括只读常量,请参阅自述文件。)
在不同的存储库中也有类似的解决方案,但据我所知,它们要么缺乏我期望从常量中得到的基本特性之一(如常量或任意类型),要么它们添加了一些使它们不那么普遍适用的深奥特性。但是Ymmv,我很感谢你的反馈。-)
编辑:为python 3添加了示例代码
注意:另一个答案似乎提供了一个更完整的实现,类似于以下内容(具有更多特性)。
首先,创建元类:
1 2 3 4 5 6 | class MetaConst(type): def __getattr__(cls, key): return cls[key] def __setattr__(cls, key, value): raise TypeError |
这样可以防止静态属性被更改。然后创建另一个使用该元类的类:
1 2 3 4 5 6 7 8 | class Const(object): __metaclass__ = MetaConst def __getattr__(self, name): return self[name] def __setattr__(self, name, value): raise TypeError |
或者,如果您使用的是python 3:
1 2 3 4 5 6 | class Const(object, metaclass=MetaConst): def __getattr__(self, name): return self[name] def __setattr__(self, name, value): raise TypeError |
这将防止更改实例属性。要使用它,请继承:
1 2 3 | class MyConst(Const): A = 1 B = 2 |
现在,直接或通过实例访问的属性应该是常量:
1 2 3 4 5 6 7 8 9 10 | MyConst.A # 1 my_const = MyConst() my_const.A # 1 MyConst.A = 'changed' # TypeError my_const.A = 'changed' # TypeError |
下面是上面的一个例子。下面是Python3的另一个示例。
属性是创建常量的一种方法。可以通过声明getter属性来实现,但忽略setter。例如:
1 2 3 4 5 | class MyFinalProperty(object): @property def name(self): return"John" |
您可以看看我写的一篇文章,了解更多使用Python属性的方法。
这里是一个"常量"类的实现,它创建具有只读(常量)属性的实例。例如,可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # ---------- Constants.py ---------- class Constants(object): """ Create objects with read-only (constant) attributes. Example: Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0) print 10 + Nums.PI print '----- Following line is deliberate ValueError -----' Nums.PI = 22 """ def __init__(self, *args, **kwargs): self._d = dict(*args, **kwargs) def __iter__(self): return iter(self._d) def __len__(self): return len(self._d) # NOTE: This is only called if self lacks the attribute. # So it does not interfere with get of 'self._d', etc. def __getattr__(self, name): return self._d[name] # ASSUMES '_..' attribute is OK to set. Need this to initialize 'self._d', etc. #If use as keys, they won't be constant. def __setattr__(self, name, value): if (name[0] == '_'): super(Constants, self).__setattr__(name, value) else: raise ValueError("setattr while locked", self) if (__name__ =="__main__"): # Usage example. Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0) print 10 + Nums.PI print '----- Following line is deliberate ValueError -----' Nums.PI = 22 |
感谢@mikegraham的frozendict,我把它作为一个起点。已更改,因此使用语法不是
多亏了@raufio的回答,才有了覆盖setattr的想法。
或者,有关具有更多功能的实现,请参见@hans_meine'sGithub的命名_常量
不幸的是,python还没有常量,这是可耻的。ES6已经向javascript添加了支持常量(https://developer.mozilla.org/en/docs/web/javascript/reference/statements/const),因为它在任何编程语言中都是非常有用的。正如在Python社区的其他答案中所回答的那样,使用约定的用户大写变量作为常量,但它不能防止代码中的任意错误。如果您愿意的话,下一步您可能会发现使用单个文件解决方案很有用(参见docstrings如何使用它)。好的。
文件常量.py好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | import collections __all__ = ('const', ) class Constant(object): """ Implementation strict constants in Python 3. A constant can be set up, but can not be changed or deleted. Value of constant may any immutable type, as well as list or set. Besides if value of a constant is list or set, it will be converted in an immutable type as next: list -> tuple set -> frozenset Dict as value of a constant has no support. >>> const = Constant() >>> del const.temp Traceback (most recent call last): NameError: name 'temp' is not defined >>> const.temp = 1 >>> const.temp = 88 Traceback (most recent call last): ... TypeError: Constanst can not be changed >>> del const.temp Traceback (most recent call last): ... TypeError: Constanst can not be deleted >>> const.I = ['a', 1, 1.2] >>> print(const.I) ('a', 1, 1.2) >>> const.F = {1.2} >>> print(const.F) frozenset([1.2]) >>> const.D = dict() Traceback (most recent call last): ... TypeError: dict can not be used as constant >>> del const.UNDEFINED Traceback (most recent call last): ... NameError: name 'UNDEFINED' is not defined >>> const() {'I': ('a', 1, 1.2), 'temp': 1, 'F': frozenset([1.2])} """ def __setattr__(self, name, value): """Declaration a constant with value. If mutable - it will be converted to immutable, if possible. If the constant already exists, then made prevent againt change it.""" if name in self.__dict__: raise TypeError('Constanst can not be changed') if not isinstance(value, collections.Hashable): if isinstance(value, list): value = tuple(value) elif isinstance(value, set): value = frozenset(value) elif isinstance(value, dict): raise TypeError('dict can not be used as constant') else: raise ValueError('Muttable or custom type is not supported') self.__dict__[name] = value def __delattr__(self, name): """Deny against deleting a declared constant.""" if name in self.__dict__: raise TypeError('Constanst can not be deleted') raise NameError("name '%s' is not defined" % name) def __call__(self): """Return all constans.""" return self.__dict__ const = Constant() if __name__ == '__main__': import doctest doctest.testmod() |
如果这还不够,请参阅完整的测试用例。好的。
1 2 3 4 5 | import decimal进口UUID导入日期时间进口统一测试From..常量导入常量类testconstant(unittest.testcase):""测试python中的实现常量""定义设置(自身):self.const=常量()定义拆卸(自行):德尔常数def test_用_-different_-variants_of_-name(self)创建_-constant_:self.const.常量=1self.assertequal(self.const.constant,1)self.const.常量=2self.assertequal(self.const.constant,2)self.const.常量=3self.assertequal(self.const.constant,3)self.const.常量=4self.assertequal(self.const.constant,4)self.const.co_ns_ta_nt=5Self.AssertEqual(self.const.co_n s_t,5)self.const.constant111=6self.assertequal(self.const.constant1111,6)def test_create_and_change_integer_常量(self):self.const.int=1234self.assertequal(self.const.int,1234)使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.int=0.211def test_create_and_change_float_常量(self):self.const.float=0.1234self.assetmequal(self.const.float,.1234)使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.float=0.211def test_create_and_change_list_constant_but_saved_as_tuple(self):self.const.list=[1,.2,none,true,datetime.date.today(),[],]self.assertEqual(self.const.list,(1,.2,none,true,datetime.date.today(),[],)self.asserttrue(isInstance(self.const.list,tuple))。使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.list=0.211def test_create_and_change_none_常量(self):self.const.none=无self.assertequal(self.const.none,无)使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.none=0.211def test_create_and_change_boolean_常量(self):self.const.boolean=真self.assertEqual(self.const.boolean,true)使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.boolean=假def test_create_and_change_string_constant(self):self.const.string="文本"self.assertEqual(self.const.string,"文本")。使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.string+='...'使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.string='test1'def test_create_dict_constant(self):使用self.assertraisesregexp(typeerror,"dict不能用作常量"):self.const.dict=def test_create_and_change_tuple_constant(self):self.const.tuple=(1,.2,none,true,datetime.date.today(),[],)self.assertEqual(self.const.tuple,(1,.2,none,true,datetime.date.today(),[],)使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.tuple='测试1'def test_create_and_change_set_constant(self):self.const.set=1,.2,none,true,datetime.date.today()self.assertEqual(self.const.set,1,.2,none,true,datetime.date.today())self.asserttrue(isInstance(self.const.set,frozenset))。使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.set=3212def test_create_and_change_frozenset_constant(self):self.const.frozenset=frozenset(1,.2,none,true,datetime.date.today())self.assertEqual(self.const.frozenset,frozenset(1,.2,none,true,datetime.date.today()))。使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.frozenset=真def测试创建和更改日期常量(self):self.const.date=日期时间。日期(1111、11、11)self.assertEqual(self.const.date,datetime.date(1111,11,11))。使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.date=真def test_create_and_change_datetime_常量(self):self.const.datetime=datetime.datetime(2000、10、10、10、10)self.assertEqual(self.const.datetime,datetime.datetime(2000,10,10,10,10,10))。使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.datetime=无def test_create_and_change_decimal_常量(self):self.const.decimal=十进制(13123.12312312321)self.assertequal(self.const.decimal,decimal.decimal(13123.12312312321))。使用self.assertraisesregexp(typeerror,"constanst can be changed"):self.const.decimal=无def test_create_and_change_timedelta_常量(self):self.const.timedelta=datetime.timedelta(天)=<hr><P>我将创建一个类来重写基本对象类的<wyn>__setattr__</wyn>方法,并用它包装我的常量,注意我使用的是python 2.7:</P>[cc lang="python"]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) |
要包装字符串:
1 2 3 4 5 6 7 8 9 10 11 | >>> constObj = const("Try to change me") >>> constObj.value 'Try to change me' >>> constObj.value ="Changed" Traceback (most recent call last): ... ValueError: Trying to change a constant value >>> constObj2 = const(" or not") >>> mutableObj = constObj.value + constObj2.value >>> mutableObj #just a string 'Try to change me or not' |
这很简单,但是如果您想使用与非常量对象相同的常量(不使用constobj.value),它将更加密集。这可能会导致问题,所以最好让
您可以使用NAMDUTUPLE作为一个解决方案来有效地创建一个常量,该常量与Java中的静态最终变量(Java常量)相同。随着解决方法的发展,它有点优雅。(更优雅的方法是简单地改进Python语言——什么样的语言可以让您重新定义
(在我写这篇文章的时候,我意识到这个问题的另一个答案是NordEtuple,但是我将继续这里,因为我将展示一个语法,它与Java中所期望的更贴近,因为不需要创建一个命名类型,NAMDUTPUE强迫你去做。)
按照您的示例,您将记住,在Java中,我们必须在某些类中定义常量;因为您没有提到类名,我们称之为EDCOX1(1)。下面是Java类:
1 2 3 | public class Foo { public static final String CONST_NAME ="Name"; } |
这是等价的python。
1 2 | from collections import namedtuple Foo = namedtuple('_Foo', 'CONST_NAME')('Name') |
我想在这里补充的关键点是,您不需要单独的
这里的第二点是,我们立即创建一个命名元组的实例,称之为
1 2 | >>> Foo.CONST_NAME 'Name' |
但您不能分配给它:
1 2 3 | >>> Foo.CONST_NAME = 'bar' … AttributeError: can't set attribute |
承认:我以为我发明了名为双重的方法,但后来我发现有人给出了类似的(虽然不太紧凑)答案。然后我还注意到在Python中什么是"命名的元组"?它指出,
请注意,不幸的是(这仍然是python),您可以完全删除整个
1 | >>> Foo = 'bar' |
(FACEPALM)
但至少我们在阻止
从技术上讲,元组被限定为一个常量,因为如果您试图更改其中一个值,则元组将引发错误。如果要声明一个具有一个值的元组,请在其唯一值后加一个逗号,如下所示:
1 | my_tuple = (0"""Or any other value""",) |
要检查此变量的值,请使用与此类似的内容:
1 2 | if my_tuple[0] == 0: #Code goes here |
如果尝试更改此值,将引发错误。
pythonic声明"常量"的方法基本上是一个模块级变量:
1 2 3 | RED = 1 GREEN = 2 BLUE = 3 |
然后编写类或函数。因为常量几乎总是整数,而且在Python中它们也是不可变的,所以修改它的可能性很小。
当然,除非您明确设置了
在python中,常量只是一个以大写字母命名的变量,单词之间用下划线分隔,
例如
周天数=7
值是可变的,正如您可以更改它一样。但是考虑到名字的规则告诉你是一个常数,你为什么要这样做?我是说,这毕竟是你的计划!
这是贯穿整个Python的方法。由于同样的原因,没有
python可以添加一个
也许有一些单元测试,在其中应用对值的更改是有意义的?看看一周8天会发生什么,即使在现实世界中,一周的天数不能改变。如果语言停止了您的异常,如果只有这一种情况,您需要打破规则……那么您将不得不停止将其声明为常量,即使它在应用程序中仍然是常量,并且只有这一个测试案例可以看到如果它被更改会发生什么。
全部大写的名称告诉您它是一个常量。这才是最重要的。不是一种强制对代码进行约束的语言,您无论如何都有权更改它。
这就是Python的哲学。
我们可以创建一个描述符对象。
1 2 3 4 5 6 7 | class Constant: def __init__(self,value=None): self.value = value def __get__(self,instance,owner): return self.value def __set__(self,instance,value): raise ValueError("You can't change a constant") |
1)如果我们想在实例级别使用常量,那么:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class A: NULL = Constant() NUM = Constant(0xFF) class B: NAME = Constant('bar') LISTA = Constant([0,1,'INFINITY']) >>> obj=A() >>> print(obj.NUM) #=> 255 >>> obj.NUM =100 Traceback (most recent call last): File"<stdin>", line 1, in <module> ValueError: You can't change a constant |
2)如果我们只想在类级别创建常量,我们可以使用一个元类作为常量(描述符对象)的容器;所有下降的类将继承我们的常量(描述符对象),而不会有任何可以修改的风险。
1 2 3 4 5 6 7 8 9 10 11 12 13 | # metaclass of my class Foo class FooMeta(type): pass # class Foo class Foo(metaclass=FooMeta): pass # I create constants in my metaclass FooMeta.NUM = Constant(0xff) FooMeta.NAME = Constant('FOO') >>> Foo.NUM #=> 255 >>> Foo.NAME #=> 'FOO' >>> Foo.NUM = 0 #=> ValueError: You can't change a constant |
如果我创建foo的子类,这个类将继承常量而不修改它们。
1 2 3 4 | class Bar(Foo): pass >>> Bar.NUM #=> 255 >>> Bar.NUM = 0 #=> ValueError: You can't change a constant |
有一种更简单的方法可以使用NamedDuple执行此操作:
1 2 3 4 5 | from collections import namedtuple def make_consts(name, **kwargs): return namedtuple(name, kwargs.keys())(**kwargs) |
使用实例
1 2 3 | CONSTS = make_consts("baz1", foo=1, bar=2) |
通过这种精确的方法,您可以为常量命名。
Python dictionaries are mutable, so they don't seem like a good way to declare constants:
1 2 3 4 5 6 | >>> constants = {"foo":1,"bar":2} >>> print constants {'foo': 1, 'bar': 2} >>> constants["bar"] = 3 >>> print constants {'foo': 1, 'bar': 3} |
也许pconst库可以帮助您(github)。
1 2 3 | from pconst import const const.APPLE_PRICE = 100 const.APPLE_PRICE = 200 |
(本段是对这些答案的评论,其中提到了
上面提到的命名双重方法绝对是创新的。不过,为了完整起见,在其官方文件的命名双重部分的末尾,它写道:
enumerated constants can be implemented with named tuples, but it is simpler and more efficient to use a simple class declaration:
1
2 class Status:
open, pending, closed = range(3)
换句话说,官方文档更喜欢使用实际的方式,而不是实际实现只读行为。我想它是另一个关于Python禅宗的例子:
Simple is better than complex.
practicality beats purity.
你只需:
1 2 | STRING_CONSTANT ="hi" NUMBER_CONSTANT = 89 |
希望一切都简单多了
In Python, constants do not exist. But you can indicate that a variable is a constant and must not be changed by adding ' _CONSTANT ' to the start of the variable name, naming the variable in BLOCK CAPITALS, and adding a comment using the hashtag (' # ') e.g. :
1 2 | normal_variable = 0 CONSTANT_variable = 1 # This is a constant - do not change its value! |
您可以使用StringVar或IntVar等,您的常量是常量
1 2 3 4 5 6 | val = 'Stackoverflow' const_val = StringVar(val) const.trace('w', reverse) def reverse(*args): const_val.set(val) |
在我的例子中,我需要不可变的bytearray来实现一个包含许多我想要确保不变的字面数字的加密库。
此答案有效,但尝试重新分配bytearray元素不会引发错误。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | def const(func): '''implement const decorator''' def fset(self, val): '''attempting to set a const raises `ConstError`''' class ConstError(TypeError): '''special exception for const reassignment''' pass raise ConstError def fget(self): '''get a const''' return func() return property(fget, fset) class Consts(object): '''contain all constants''' @const def C1(): '''reassignment to C1 fails silently''' return bytearray.fromhex('deadbeef') @const def pi(): '''is immutable''' return 3.141592653589793 |
常量是不可变的,但常量bytearray分配会自动失败:
1 2 3 4 5 6 7 8 9 10 11 12 | >>> c = Consts() >>> c.pi = 6.283185307179586 # (https://en.wikipedia.org/wiki/Tau_(2%CF%80)) Traceback (most recent call last): File"<stdin>", line 1, in <module> File"consts.py", line 9, in fset raise ConstError __main__.ConstError >>> c.C1[0] = 0 >>> c.C1[0] 222 >>> c.C1 bytearray(b'\xde\xad\xbe\xef') |
一种更强大、更简单、甚至可能更"pythonic"的方法涉及到使用memoryview对象(缓冲区对象在<=python-2.6中)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import sys PY_VER = sys.version.split()[0].split('.') if int(PY_VER[0]) == 2: if int(PY_VER[1]) < 6: raise NotImplementedError elif int(PY_VER[1]) == 6: memoryview = buffer class ConstArray(object): '''represent a constant bytearray''' def __init__(self, init): ''' create a hidden bytearray and expose a memoryview of that bytearray for read-only use ''' if int(PY_VER[1]) == 6: self.__array = bytearray(init.decode('hex')) else: self.__array = bytearray.fromhex(init) self.array = memoryview(self.__array) def __str__(self): return str(self.__array) def __getitem__(self, *args, **kwargs): return self.array.__getitem__(*args, **kwargs) |
constaray项分配是一个
1 2 3 4 5 6 7 | >>> C1 = ConstArray('deadbeef') >>> C1[0] = 0 Traceback (most recent call last): File"<stdin>", line 1, in <module> TypeError: 'ConstArray' object does not support item assignment >>> C1[0] 222 |
如果你想要常量而不关心它们的值,这里有一个技巧:
只需定义空类。
例如:
1 2 3 4 | class RED: pass class BLUE: pass |
我为python const编写了一个util lib:科皮斯特-皮皮支持str,int,float,datetime
const字段实例将保留其基类型行为。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from __future__ import print_function from kkconst import ( BaseConst, ConstFloatField, ) class MathConst(BaseConst): PI = ConstFloatField(3.1415926, verbose_name=u"Pi") E = ConstFloatField(2.7182818284, verbose_name=u"mathematical constant") # Euler's number" GOLDEN_RATIO = ConstFloatField(0.6180339887, verbose_name=u"Golden Ratio") magic_num = MathConst.GOLDEN_RATIO assert isinstance(magic_num, ConstFloatField) assert isinstance(magic_num, float) print(magic_num) # 0.6180339887 print(magic_num.verbose_name) # Golden Ratio |
更多详细信息用法,您可以阅读pypi url:Pypi或Github
没有完美的方法可以做到这一点。据我所知,大多数程序员只是将标识符大写,所以pi=3.142可以很容易地理解为常量。
另一方面,如果你想要一个常数,我不确定你会找到它。不管你做什么,总会有一些编辑"常数"的方法,所以它不会真的是一个常数。下面是一个非常简单、肮脏的例子:
1 2 3 4 5 6 7 8 9 10 | def define(name, value): if (name + str(id(name))) not in globals(): globals()[name + str(id(name))] = value def constant(name): return globals()[name + str(id(name))] define("PI",3.142) print(constant("PI")) |
这看起来会使PHP样式成为常量。
实际上,一个人改变价值所需要的就是:
1 | globals()["PI"+str(id("PI"))] = 3.1415 |
对于您在这里找到的所有其他解决方案来说,这是相同的——即使是那些聪明的解决方案,它们可以创建一个类并重新定义set属性方法——它们总是有一种解决方法的。Python就是这样。
我的建议是避免所有的麻烦,只是大写您的标识符。它不是一个适当的常数,但同样的,没有什么。
你可以用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import collections import itertools def Constants(Name, *Args, **Kwargs): t = collections.namedtuple(Name, itertools.chain(Args, Kwargs.keys())) return t(*itertools.chain(Args, Kwargs.values())) >>> myConstants = Constants('MyConstants', 'One', 'Two', Three = 'Four') >>> print myConstants.One One >>> print myConstants.Two Two >>> print myConstants.Three Four >>> myConstants.One = 'Two' Traceback (most recent call last): File"<stdin>", line 1, in <module> AttributeError: can't set attribute |
可以将常量包装在numpy数组中,将其标记为只写,并始终按索引0调用它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | import numpy as np # declare a constant CONSTANT = 'hello' # put constant in numpy and make read only CONSTANT = np.array([CONSTANT]) CONSTANT.flags.writeable = False # alternatively: CONSTANT.setflags(write=0) # call our constant using 0 index print 'CONSTANT %s' % CONSTANT[0] # attempt to modify our constant with try/except new_value = 'goodbye' try: CONSTANT[0] = new_value except: print"cannot change CONSTANT to '%s' it's value '%s' is immutable" % ( new_value, CONSTANT[0]) # attempt to modify our constant producing ValueError CONSTANT[0] = new_value >>> CONSTANT hello cannot change CONSTANT to 'goodbye' it's value 'hello' is immutable Traceback (most recent call last): File"shuffle_test.py", line 15, in <module> CONSTANT[0] = new_value ValueError: assignment destination is read-only |
当然,这只保护numpy的内容,而不是变量"constant"本身;您仍然可以这样做:
1 | CONSTANT = 'foo' |
而
虽然…我想如果你在某个时候把它改成
1 | CONSTANT = [1,2,3] |
现在你不会再有打字错误了。嗯…
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.setflags.html网站
扩展raufio的答案,添加repr返回值。
1 2 3 4 5 6 7 8 9 10 | 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中创建一个常量变量。做一个一维元组。
1 | myconstant_var = (10,) |
就是这样。现在变量myinstant变量不能更改
您可以在下一个类的帮助下模拟常量变量。使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # Const const = Const().add(two=2, three=3) print 'const.two: ', const.two print 'const.three: ', const.three const.add(four=4) print 'const.four: ', const.four #const.four = 5 # a error here: four is a constant const.add(six=6) print 'const.six: ', const.six const2 = Const().add(five=5) # creating a new namespace with Const() print 'const2.five: ', const2.five #print 'const2.four: ', const2.four # a error here: four does not exist in const2 namespace const2.add(five=26) |
当要启动新的常量命名空间时,请调用构造函数。请注意,当martelli的const类不是时,该类受到意外修改序列类型常量的保护。
资料来源如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | from copy import copy class Const(object): "A class to create objects with constant fields." def __init__(self): object.__setattr__(self, '_names', []) def add(self, **nameVals): for name, val in nameVals.iteritems(): if hasattr(self, name): raise ConstError('A field with a name \'%s\' is already exist in Const class.' % name) setattr(self, name, copy(val)) # set up getter self._names.append(name) return self def __setattr__(self, name, val): if name in self._names: raise ConstError('You cannot change a value of a stored constant.') object.__setattr__(self, name, val) |
好。。尽管这已经过时了,让我在这里加上我的2美分:—)
1 2 3 4 5 6 7 8 | class ConstDict(dict): def __init__(self, *args, **kwargs): super(ConstDict, self).__init__(*args, **kwargs) def __setitem__(self, key, value): if key in self: raise ValueError("Value %s already exists" % (key)) super(ConstDict, self).__setitem__(key, value) |
您可以避免在那里发生任何更新,而不是让ValueError中断。这样做的一个好处是,可以在程序中动态添加常量,但一旦设置了常量,就不能更改。此外,您还可以在设置常量之前添加任何规则或任何内容(例如,键在设置键之前必须是字符串或小写字符串或大写字符串等)。
但是,我没有看到在Python中设置常量的重要性。没有任何优化可以像在C中那样发生,因此我猜这是不需要的。
python字典一旦声明就不可更改,可以用作常量。
[cc lang="python"]my_consts={"TIMEOUT":300,"RETRIES":10,"STATE":"happy