有没有办法在Python中声明常量? 在Java中,我们可以按以下方式创建常量值:

public static final String CONST_NAME = "Name";

Python中上述Java常量声明的等效项是什么?


#1楼

我将创建一个覆盖基础对象类的__setattr__方法的类,并用其包装我的常量,请注意,我使用的是python 2.7:

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)

要包装字符串:

>>> 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),则会更加费劲。 这可能会导致问题,因此最好使.value保持显示状态,并知道您正在使用常量进行操作(尽管这不是最“ pythonic”的方式)。


#2楼

扩展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'


#3楼

除了两个最重要的答案(仅使用带大写名称的变量,或使用属性将值设为只读)外,我还要提到可以使用元类来实现命名常量。 我在GitHub上提供了一个使用元类的非常简单的解决方案,如果您希望这些值对它们的类​​型/名称有更多的了解,这可能会有所帮助:

>>> 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,感谢您的反馈。 :-)


#4楼

这是“常量”类的实现,该类创建具有只读(常量)属性的实例。 例如,可以使用Nums.PI来获取已初始化为3.14159的值,并且Nums.PI = 22会引发异常。

# ---------- 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.PIprint '----- 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.PIprint '----- Following line is deliberate ValueError -----'Nums.PI = 22

感谢@MikeGraham的FrozenDict ,我以此作为起点。 已更改,因此使用语法为Nums.ONE ,而不是Nums['ONE']

并感谢@Raufio的回答,以提供覆盖__ setattr __的想法。

有关更多功能的实现,请参见GitHub上的 @Hans_meine的named_constants


#5楼

我最近发现了一个非常简洁的更新,它会自动引发有意义的错误消息并阻止通过__dict__访问:

class CONST(object):__slots__ = ()FOO = 1234CONST = CONST()# ----------print(CONST.FOO)    # 1234CONST.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'

我们将自己定义为使自己成为实例,然后使用插槽确保不会添加任何其他属性。 这也会删除__dict__访问路径。 当然,整个对象仍然可以重新定义。

编辑-原始解决方案

我可能在这里缺少技巧,但这似乎对我有用:

class CONST(object):FOO = 1234def __setattr__(self, *_):passCONST = CONST()#----------print CONST.FOO    # 1234CONST.FOO = 4321
CONST.BAR = 5678print CONST.FOO    # Still 1234!
print CONST.BAR    # Oops AttributeError

创建实例可以使魔术__setattr__方法__setattr__并拦截设置FOO变量的尝试。 如果愿意,可以在这里抛出异常。 通过类名称实例化实例可防止直接通过类进行访问。

一个值总让人痛苦,但是您可以将很多附加到CONST对象上。 拥有上流社会的阶级名称似乎也有点古怪,但我认为总体上来说它是很简洁的。


#6楼

不,那里没有。 您无法在Python中将变量或值声明为常量。 只是不要更改它。

如果您在上课,则等效项为:

class Foo(object):CONST_NAME = "Name"

如果不是,那只是

CONST_NAME = "Name"

但是您可能想看看Alex Martelli编写的Python中的代码片段Constants 。


从Python 3.8开始,有一个typing.Final变量注释将告诉静态类型检查器(如mypy)不应重新分配您的变量。 这与Java的final最接近。 但是,它实际上并不能阻止重新分配

from typing import Finala: Final = 1# Executes fine, but mypy will report an error if you run mypy on this:
a = 2

#7楼

在Python中,人们使用命名约定,例如__method表示私有方法,使用_method表示受保护方法,而不是用语言来强制执行某些操作。

因此,以相同的方式,您可以简单地将常量声明为所有大写字母,例如

MY_CONSTANT = "one"

如果希望此常量永远不变,则可以加入属性访问并进行技巧,但是更简单的方法是声明一个函数

def MY_CONSTANT():return "one"

唯一的问题是无处不在,您将必须执行MY_CONSTANT(),但再次使用MY_CONSTANT = "one"是python(通常)中的正确方法。

您还可以使用namedtuple创建常量:

>>> 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

#8楼

Python声明“常量”的方式基本上是模块级变量:

RED = 1
GREEN = 2
BLUE = 3

然后编写您的类或函数。 由于常量几乎总是整数,并且在Python中也是不变的,因此更改它的机会很小。

当然,除非您明确设置RED = 2


#9楼

没有其他语言中的const关键字,但是可以创建一个具有“ getter函数”的属性来读取数据,而没有“ setter函数”的属性来重写数据。 实质上,这可以防止标识符被更改。

这是使用类属性的替代实现:

请注意,对于想知道常量的读者来说,这段代码远非易事。 请参阅下面的说明

def constant(f):def fset(self, value):raise TypeErrordef fget(self):return f()return property(fget, fset)class _Const(object):@constantdef FOO():return 0xBAADFACE@constantdef BAR():return 0xDEADBEEFCONST = _Const()print CONST.FOO
##3131964110CONST.FOO = 0
##Traceback (most recent call last):
##    ...
##    CONST.FOO = 0
##TypeError: None

代码说明:

  1. 定义一个接受表达式的函数constant ,并使用它构造一个“ getter”-一个仅返回表达式值的函数。
  2. setter函数引发TypeError,因此它是只读的
  3. 使用我们刚刚创建的constant函数作为修饰,以快速定义只读属性。

并且以其他更老式的方式:

(代码很棘手,下面有更多说明)

class _Const(object):@applydef FOO():def fset(self, value):raise TypeErrordef fget(self):return 0xBAADFACEreturn property(**locals())CONST = _Const()print CONST.FOO
##3131964110CONST.FOO = 0
##Traceback (most recent call last):
##    ...
##    CONST.FOO = 0
##TypeError: None

请注意,@ apply装饰器似乎已被弃用。

  1. 为了定义标识符FOO,fir定义了两个函数(fset,fget-名称由我选择)。
  2. 然后使用内置的property函数构造可以“设置”或“获取”的对象。
  3. 注意,该property函数的前两个参数名为fsetfget
  4. 使用我们为自己的getter和setter选择这些名称的事实,并使用应用于该范围的所有本地定义的**(双星号)创建关键字字典,以将参数传递给property函数

#10楼

就我而言,我需要一个不可变的字节数组来实现一个加密库的实现,该库包含许多我想确保常量的文字数字。

此答案有效,但尝试重新分配字节数组元素不会引发错误。

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'''passraise ConstErrordef fget(self):'''get a const'''return func()return property(fget, fset)class Consts(object):'''contain all constants'''@constdef C1():'''reassignment to C1 fails silently'''return bytearray.fromhex('deadbeef')@constdef pi():'''is immutable'''return 3.141592653589793

常量是不可变的,但是常量字节数组的分配会静默失败:

>>> 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 fsetraise ConstError
__main__.ConstError
>>> c.C1[0] = 0
>>> c.C1[0]
222
>>> c.C1
bytearray(b'\xde\xad\xbe\xef')

一种更强大,更简单,甚至可能更多的“ pythonic”方法涉及使用memoryview对象(<= python-2.6中的缓冲区对象)。

import sysPY_VER = sys.version.split()[0].split('.')if int(PY_VER[0]) == 2:if int(PY_VER[1]) < 6:raise NotImplementedErrorelif int(PY_VER[1]) == 6:memoryview = bufferclass ConstArray(object):'''represent a constant bytearray'''def __init__(self, init):'''create a hidden bytearray and expose a memoryview of that bytearray forread-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)

ConstArray项分配是TypeError

>>> 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

#11楼

编辑:添加了Python 3的示例代码

注意: 这个其他答案似乎提供了与以下类似的更完整的实现(具有更多功能)。

首先,创建一个元类 :

class MetaConst(type):def __getattr__(cls, key):return cls[key]def __setattr__(cls, key, value):raise TypeError

这样可以防止更改静态属性。 然后制作另一个使用该元类的类:

class Const(object):__metaclass__ = MetaConstdef __getattr__(self, name):return self[name]def __setattr__(self, name, value):raise TypeError

或者,如果您使用的是Python 3:

class Const(object, metaclass=MetaConst):def __getattr__(self, name):return self[name]def __setattr__(self, name, value):raise TypeError

这样可以防止实例道具被更改。 要使用它,请继承:

class MyConst(Const):A = 1B = 2

现在,直接或通过实例访问的道具应该是恒定的:

MyConst.A
# 1
my_const = MyConst()
my_const.A
# 1MyConst.A = 'changed'
# TypeError
my_const.A = 'changed'
# TypeError

这是上面的例子。 这是 Python 3 的另一个示例。


#12楼

我为python const写了一个util lib: kkconst-pypi支持str,int,float,datetime

const字段实例将保持其基本类型行为。

例如:

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网址: pypi或github


#13楼

从技术上讲,元组可以视为常量,因为如果尝试更改其值之一,则元组会引发错误。 如果要声明具有一个值的元组,则在其唯一值后放置一个逗号,如下所示:

my_tuple = (0 """Or any other value""",)

要检查此变量的值,请使用类似于以下内容的方法:

if my_tuple[0] == 0:#Code goes here

如果尝试更改该值,将引发错误。


#14楼

您可以使用namedtuple作为解决方法,以有效地创建一个常量,该常量的作用方式与Java中的静态最终变量(Java“常量”)相同。 随着变通办法的进行,它有点优雅。 (一种更优雅的方法是简单地改进Python语言--哪种语言可以让您重新定义math.pi ?-但我离题了。)

(在写这篇文章时,我意识到提到了namedtuple这个问题的另一个答案,但是我将继续在这里,因为我将展示一种语法,该语法与Java期望的语法更加相似,因为无需创建named 键入为namedtuple强制执行。)

在您的示例之后,您会记住,在Java中,我们必须在某个类中定义常量; 因为您没有提到类名,所以我们将其称为Foo 。 这是Java类:

public class Foo {public static final String CONST_NAME = "Name";
}

这是等效的Python。

from collections import namedtuple
Foo = namedtuple('_Foo', 'CONST_NAME')('Name')

我想在此处添加的要点是,您不需要单独的Foo类型(即使听起来像是矛盾的词,“匿名命名的元组”也将是不错的选择),所以我们将我们的_Foo命名为希望它_Foo了逃脱到导入模块。

这里的第二点是,我们立即创建 nametuple 的实例 ,将其称为Foo ; 无需单独执行此操作(除非您愿意)。 现在,您可以执行Java中的操作:

>>> Foo.CONST_NAME
'Name'

但是您不能分配给它:

>>> Foo.CONST_NAME = 'bar'
…
AttributeError: can't set attribute

致谢:我以为我发明了namedtuple方法,但是后来我看到别人也给出了类似的答案(尽管不太紧凑)。 然后我还注意到Python中什么是“命名元组”? ,它指出sys.version_info现在是一个namedtuple,因此Python标准库也许早就提出了这个想法。

请注意,不幸的是(仍然是Python),您可以完全擦除整个Foo分配:

>>> Foo = 'bar'

(facepalm)

但是至少我们要防止Foo.CONST_NAME值被更改,这总比没有好。 祝好运。


#15楼

不幸的是,Python还没有常量,所以很遗憾。 ES6已经在JavaScript中添加了支持常量( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const ),因为它在任何编程语言中都是非常有用的。 正如Python社区中其他答案所回答的那样,使用约定-用户大写变量作为常量,但是它不能防止代码中的任意错误。 如果愿意的话,接下来可能会发现有用的单文件解决方案(请参阅docstrings如何使用它)。

文件constants.py

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 -> tupleset -> frozensetDict as value of a constant has no support.>>> const = Constant()>>> del const.tempTraceback (most recent call last):NameError: name 'temp' is not defined>>> const.temp = 1>>> const.temp = 88Traceback (most recent call last):...TypeError: Constanst can not be changed>>> del const.tempTraceback (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.UNDEFINEDTraceback (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] = valuedef __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 doctestdoctest.testmod()

如果这还不够,请查看完整的测试用例。

import decimal
import uuid
import datetime
import unittestfrom ..constants import Constantclass TestConstant(unittest.TestCase):"""Test for implementation constants in the Python"""def setUp(self):self.const = Constant()def tearDown(self):del self.constdef test_create_constant_with_different_variants_of_name(self):self.const.CONSTANT = 1self.assertEqual(self.const.CONSTANT, 1)self.const.Constant = 2self.assertEqual(self.const.Constant, 2)self.const.ConStAnT = 3self.assertEqual(self.const.ConStAnT, 3)self.const.constant = 4self.assertEqual(self.const.constant, 4)self.const.co_ns_ta_nt = 5self.assertEqual(self.const.co_ns_ta_nt, 5)self.const.constant1111 = 6self.assertEqual(self.const.constant1111, 6)def test_create_and_change_integer_constant(self):self.const.INT = 1234self.assertEqual(self.const.INT, 1234)with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.INT = .211def test_create_and_change_float_constant(self):self.const.FLOAT = .1234self.assertEqual(self.const.FLOAT, .1234)with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.FLOAT = .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))with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.LIST = .211def test_create_and_change_none_constant(self):self.const.NONE = Noneself.assertEqual(self.const.NONE, None)with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.NONE = .211def test_create_and_change_boolean_constant(self):self.const.BOOLEAN = Trueself.assertEqual(self.const.BOOLEAN, True)with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.BOOLEAN = Falsedef test_create_and_change_string_constant(self):self.const.STRING = "Text"self.assertEqual(self.const.STRING, "Text")with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.STRING += '...'with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.STRING = 'TEst1'def test_create_dict_constant(self):with self.assertRaisesRegexp(TypeError, 'dict can not be used as constant'):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(), [], {}))with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.TUPLE = 'TEst1'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))with self.assertRaisesRegexp(TypeError, 'Constanst can not 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()}))with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.FROZENSET = Truedef test_create_and_change_date_constant(self):self.const.DATE = datetime.date(1111, 11, 11)self.assertEqual(self.const.DATE, datetime.date(1111, 11, 11))with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.DATE = Truedef test_create_and_change_datetime_constant(self):self.const.DATETIME = datetime.datetime(2000, 10, 10, 10, 10)self.assertEqual(self.const.DATETIME, datetime.datetime(2000, 10, 10, 10, 10))with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.DATETIME = Nonedef test_create_and_change_decimal_constant(self):self.const.DECIMAL = decimal.Decimal(13123.12312312321)self.assertEqual(self.const.DECIMAL, decimal.Decimal(13123.12312312321))with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.DECIMAL = Nonedef test_create_and_change_timedelta_constant(self):self.const.TIMEDELTA = datetime.timedelta(days=45)self.assertEqual(self.const.TIMEDELTA, datetime.timedelta(days=45))with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.TIMEDELTA = 1def test_create_and_change_uuid_constant(self):value = uuid.uuid4()self.const.UUID = valueself.assertEqual(self.const.UUID, value)with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):self.const.UUID = []def test_try_delete_defined_const(self):self.const.VERSION = '0.0.1'with self.assertRaisesRegexp(TypeError, 'Constanst can not be deleted'):del self.const.VERSIONdef test_try_delete_undefined_const(self):with self.assertRaisesRegexp(NameError, "name 'UNDEFINED' is not defined"):del self.const.UNDEFINEDdef test_get_all_defined_constants(self):self.assertDictEqual(self.const(), {})self.const.A = 1self.assertDictEqual(self.const(), {'A': 1})self.const.B = "Text"self.assertDictEqual(self.const(), {'A': 1, 'B': "Text"})

优点:1.可以访问整个项目的所有常量2.严格控制常量的值

缺乏:1.不支持自定义类型和类型“ dict”

笔记:

  1. 经过Python3.4和Python3.5的测试(我使用的是“ tox”)

  2. 测试环境:

$ uname -a
Linux wlysenko-Aspire 3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

#16楼

您可以将常量包装在numpy数组中,将其标记为只写,并始终按索引零对其进行调用。

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”本身; 您仍然可以:

CONSTANT = 'foo'

CONSTANT会发生变化,但是在以后第一次在脚本中调用CONSTANT[0]时,它将迅速引发TypeError。

虽然...我想如果你在某个时候将其更改为

CONSTANT = [1,2,3]

现在您不会再收到TypeError了。 嗯...

https://docs.scipy.org/doc/numpy/reference/generation/numpy.ndarray.setflags.html


#17楼

我们可以创建一个描述符对象。

class Constant:def __init__(self,value=None):self.value = valuedef __get__(self,instance,owner):return self.valuedef __set__(self,instance,value):raise ValueError("You can't change a constant")

1)如果我们想在实例级别使用常量,则:

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 =100Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: You can't change a constant

2)如果我们只想在类级别创建常量,则可以使用一个元类作为常量(我们的描述符对象)的容器; 所有下降的类都将继承我们的常量(我们的描述符对象),而没有任何可以修改的风险。

# 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的子类,则该类将继承常量,而不能修改它们

class Bar(Foo): pass>>> Bar.NUM  #=> 255
>>> Bar.NUM = 0  #=> ValueError: You can't change a constant

#18楼

属性是创建常量的一种方法。 您可以通过声明一个getter属性,而忽略setter来做到这一点。 例如:

class MyFinalProperty(object):@propertydef name(self):return "John"

您可以看一下我写的一篇文章,以找到更多使用Python属性的方法。


#19楼

如果您想要常量并且不关心它们的值,这是一个技巧:

只需定义空类。

例如:

class RED: pass
class BLUE: pass

#20楼

Python没有常数。

也许最简单的选择是为其定义一个函数:

def MY_CONSTANT():return 42

MY_CONSTANT()现在具有常量的所有功能(加上一些讨厌的括号)。


#21楼

您可以使用StringVar或IntVar等,您的常数为

val = 'Stackoverflow'
const_val = StringVar(val)
const.trace('w', reverse)def reverse(*args):const_val.set(val)

#22楼

您可以使用collections.namedtupleitertools来做到这一点:

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

#23楼

在Python中,常数不存在。 但是您可以通过在变量名称的开头添加CONST_CONSTANT_或在BLOCK CAPITALS中命名该变量,并在注释中声明它是CONSTANT_来表明变量是常量,并且不得更改:

    myVariable = 0CONST_daysInWeek = 7    # This is a constant - do not change its value.   CONSTANT_daysInMonth = 30 # This is also a constant - do not change this value.

#24楼

在python中,常数只是一个变量,其名称全部用大写字母表示,单词之间用下划线字符分隔,

例如

DAYS_IN_WEEK = 7

该值是可变的,因为您可以更改它。 但是,鉴于名称规则告诉您一个常量,为什么呢? 我的意思是,这毕竟是您的程序!

这是整个python采取的方法。 出于相同原因,没有private关键字。 在名称前加上下划线,您将知道该名称是私有的。 代码可能会违反规则……就像程序员可以删除私有关键字一样。

Python可以添加const关键字...但是程序员可以删除关键字,然后根据需要更改常量,但是为什么这样做呢? 如果您想违反规则,则可以随时更改规则。 但是,如果名称使意图清楚,为什么还要烦扰规则呢?

也许在某些单元测试中,对价值进行更改有意义吗? 即使在现实世界中,一周中的天数无法更改,也要查看一周8天的情况。 如果这种语言阻止了您的出现,那么在这种情况下您就需要打破规则……您将不得不停止将其声明为常量,即使它在应用程序中仍然是常量,并且只是这个测试用例,查看更改后会发生什么。

所有大写的名称告诉您它应为常数。 那很重要。 不是一种语言会强制对代码施加约束,但是您仍然可以更改代码。

那就是python的理念。


#25楼

只需执行以下操作即可:

STRING_CONSTANT = "hi"
NUMBER_CONSTANT = 89

希望可以使一切变得简单


#26楼

没有完美的方法可以做到这一点。 据我了解,大多数程序员只会将标识符大写,因此PI = 3.142很容易理解为常数。

另一方面,如果您想要某种实际上像常量的东西,我不确定您会找到它。 无论您做什么,总会有某种方式来编辑“常量”,因此它并不是真正的常量。 这是一个非常简单,肮脏的示例:

def define(name, value):if (name + str(id(name))) not in globals():globals()[name + str(id(name))] = valuedef constant(name):return globals()[name + str(id(name))]define("PI",3.142)print(constant("PI"))

看起来它将使一个PHP样式的常量。

实际上,某人更改值所需的一切是这样的:

globals()["PI"+str(id("PI"))] = 3.1415

在这里可以找到的所有其他解决方案都是相同的,即使是聪明的解决方案也可以创建类并重新定义set属性方法,但总会有解决之道。 Python就是这样。

我的建议是避免所有麻烦,只使用标识符大写。 它实际上不是一个适当的常数,但是再也没有。


#27楼

(本段的意思是在这里和那里对那些答案的评论,其中提到了namedtuple ,但是它太长了,无法放入评论中,所以就到这里了。)

上面提到的namedtuple方法绝对是创新的。 但是,为了完整起见,在其官方文档的NamedTuple部分的末尾,其内容为:

枚举常量可以用命名元组实现,但是使用简单的类声明更简单,更高效:

 class Status: open, pending, closed = range(3) 

换句话说,官方文档倾向于使用一种实用的方式,而不是实际实现只读行为。 我想这成为Python Zen的另一个例子:

简单胜于复杂。

实用性胜过纯度。


#28楼

有一个更干净的方法可以使用namedtuple做到这一点:

from collections import namedtupledef make_consts(name, **kwargs):return namedtuple(name, kwargs.keys())(**kwargs)

使用范例

CONSTS = make_consts("baz1",foo=1,bar=2)

通过这种精确的方法,您可以为常量命名空间。


#29楼

也许pconst库会为您提供帮助( github )。

$ pip install pconst

from pconst import const
const.APPLE_PRICE = 100
const.APPLE_PRICE = 200

[Out] Constant value of "APPLE_PRICE" is not editable.


#30楼

PEP 591具有“最终”限定词。 强制执行取决于类型检查器。

因此,您可以执行以下操作:

MY_CONSTANT: Final = 12407

#31楼

Python字典是可变的,因此它们似乎不是声明常量的好方法:

>>> constants = {"foo":1, "bar":2}
>>> print constants
{'foo': 1, 'bar': 2}
>>> constants["bar"] = 3
>>> print constants
{'foo': 1, 'bar': 3}

如何在Python中创建常量?相关推荐

  1. 如何在 Python 中创建一个简单的神经网络

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 引言 在过去的几十年里,机器学习对世界产生了巨大的影响,而且它的普 ...

  2. python计算均方根误差_如何在Python中创建线性回归机器学习模型?「入门篇」

    线性回归和逻辑回归是当今很受欢迎的两种机器学习模型. 本文将教你如何使用 scikit-learn 库在Python中创建.训练和测试你的第一个线性.逻辑回归机器学习模型,本文适合大部分的新人小白. ...

  3. python面试题之如何在Python中创建自己的包

    Python中创建包是比较方便的,只需要在当前目录建立一个文件夹, 文件夹中包含一个__init__.py文件和若干个模块文件, 其中__init__.py可以是一个空文件,但还是建议将包中所有需要导 ...

  4. 3.3:如何在Python中创建文件?

    一.在Python中创建文件的主要步骤包括: (1)使用open()函数打开一个文件对象. (2)使用文件对象的write()方法向文件中写入内容. (3)关闭文件对象,以释放文件资源. 二.open ...

  5. 如何在Python中创建Excel表格

    之前在学习os模块中,我们知道了如何创建一个txt格式的文件(具体操作见https://mp.csdn.net/postedit/80903024) 但是当我们爬取一些小说或一些图片时,我们需要分类管 ...

  6. 我们如何在Python中创建多行注释?

    When we need to comment on multiple lines/statements, there are two ways to do this, either comment ...

  7. python中怎么创建一个词典_如何在Python中创建字典词典

    所以我正在学习一个自然语言处理类,我需要创建一个trigram语言模型来生成随机文本,这些文本在一定程度上基于一些样本数据看起来"逼真". 根本需要创建一个"三元组&qu ...

  8. python列表有固定大小吗_如何在python中创建固定大小的列表?

    (tl:dr:对您的问题的确切答案是numpy.empty或numpy.empty_like,但是您可能不在乎,可以使用myList = [None]*10000.) 简单方法 您可以将列表初始化为所 ...

  9. python生成指定长度的列表_如何在python中创建固定大小列表?

    (tl;博士:您问题的确切答案是numpy.empty_like或x = list(size=10000),但您可能不在乎,可以使用myList = [None]*10000逃脱.) 简单的方法 您可 ...

最新文章

  1. mysql join order by_MySQL 14 慢查询优化join、order by、group by
  2. 一次 Nacos 的踩坑记录!
  3. MySQL数据库数据类型以及INT(M)的含义
  4. python绘制动态图-Python利用Echarts绘制动态交互图:快速入门
  5. java jdkxp32_java运行环境(jre-8u65-windows-i586) 官方安装版 32位
  6. windows phone 操作 http异步返回结果
  7. Scala 隐式(implicit)详解
  8. android如何让service不被杀死-提高进程优先级
  9. 前端学习(3271):js中this的使用
  10. 钱荒下银行理财收益率角逐:邮储银行垫底
  11. LINUX上ZIP的使用
  12. 音视频学习系列第(四)篇---视频的采集预览
  13. DivCss 布局应用案例实践总结
  14. ISO文件编辑工具-UltraISO软碟通提供下载
  15. php简易微博系统,基于html、css、PHP开发一个简单的微型博客系统(微博)
  16. mysql多表联合查询 去重_MySQL多表联合查询
  17. 如果你想学好Py thon,我这里有几本电子书想送你
  18. Nagios下载安装配置
  19. UI设计常用软件有哪些?
  20. SOME/IP开源库Vsomeip分析

热门文章

  1. 如何开具和交付给客户电子发票
  2. 百度SMS发送短信C#
  3. bootstrap课程4 bootstrap的css样式有哪些内容需要注意
  4. 11-4实战上色及修复照片
  5. 使用excel2003中的solver解决最优化问题
  6. 使用用WCF中的双工(Duplex)模式将广告图片推送到每个Winform客户端机子上
  7. linux文件IO的操作
  8. 分析C#中Dialog控件(转)
  9. NickLee UI中间件 for asp.net 2.0版本
  10. zabbix-agent自定义监控项