博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何在Python中创建常量?
阅读量:3577 次
发布时间:2019-05-20

本文共 25366 字,大约阅读时间需要 84 分钟。

有没有办法在中声明常量? 在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楼

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

>>> from named_constants import Constants>>> class Colors(Constants):...     black = 0...     red = 1...     white = 15...>>> c = Colors.black>>> c == 0True>>> cColors.black>>> c.name()'black'>>> Colors(0) is cTrue

这是稍微高级些的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.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

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

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

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


#5楼

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

class CONST(object):    __slots__ = ()    FOO = 1234CONST = CONST()# ----------print(CONST.FOO)    # 1234CONST.FOO = 4321              # AttributeError: 'CONST' object attribute 'FOO' is read-onlyCONST.__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 = 1234    def __setattr__(self, *_):        passCONST = CONST()#----------print CONST.FOO    # 1234CONST.FOO = 4321CONST.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 3.8开始,有一个变量注释将告诉静态类型检查器(如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(通常)中的正确方法。

您还可以使用创建常量:

>>> from collections import namedtuple>>> Constants = namedtuple('Constants', ['pi', 'e'])>>> constants = Constants(3.14, 2.718)>>> constants.pi3.14>>> constants.pi = 3Traceback (most recent call last):  File "
", line 1, in
AttributeError: can't set attribute

#8楼

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

RED = 1GREEN = 2BLUE = 3

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

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


#9楼

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

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

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

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 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):    @apply    def FOO():        def fset(self, value):            raise TypeError        def fget(self):            return 0xBAADFACE        return 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'''            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

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

>>> c = Consts()>>> c.pi = 6.283185307179586  # (https://en.wikipedia.org/wiki/Tau_(2%CF%80))Traceback (most recent call last):  File "
", line 1, in
File "consts.py", line 9, in fset raise ConstError__main__.ConstError>>> c.C1[0] = 0>>> c.C1[0]222>>> c.C1bytearray(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 NotImplementedError    elif 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 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)

ConstArray项分配是TypeError

>>> C1 = ConstArray('deadbeef')>>> C1[0] = 0Traceback (most recent call last):  File "
", line 1, in
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__ = MetaConst    def __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 = 1    B = 2

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

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

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


#12楼

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

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

例如:

from __future__ import print_functionfrom 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_RATIOassert isinstance(magic_num, ConstFloatField)assert isinstance(magic_num, float)print(magic_num)  # 0.6180339887print(magic_num.verbose_name)  # Golden Ratio

更多详细信息用法,您可以阅读pypi网址: 或


#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 namedtupleFoo = 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方法,但是后来我看到别人也给出了类似的答案(尽管不太紧凑)。 然后我还注意到 ,它指出现在是一个namedtuple,因此Python标准库也许早就提出了这个想法。

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

>>> Foo = 'bar'

(facepalm)

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


#15楼

不幸的是,Python还没有常量,所以很遗憾。 ES6已经在JavaScript中添加了支持常量( ),因为它在任何编程语言中都是非常有用的。 正如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 -> 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()

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

import decimalimport uuidimport datetimeimport 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.const    def test_create_constant_with_different_variants_of_name(self):        self.const.CONSTANT = 1        self.assertEqual(self.const.CONSTANT, 1)        self.const.Constant = 2        self.assertEqual(self.const.Constant, 2)        self.const.ConStAnT = 3        self.assertEqual(self.const.ConStAnT, 3)        self.const.constant = 4        self.assertEqual(self.const.constant, 4)        self.const.co_ns_ta_nt = 5        self.assertEqual(self.const.co_ns_ta_nt, 5)        self.const.constant1111 = 6        self.assertEqual(self.const.constant1111, 6)    def test_create_and_change_integer_constant(self):        self.const.INT = 1234        self.assertEqual(self.const.INT, 1234)        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):            self.const.INT = .211    def test_create_and_change_float_constant(self):        self.const.FLOAT = .1234        self.assertEqual(self.const.FLOAT, .1234)        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):            self.const.FLOAT = .211    def 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 = .211    def test_create_and_change_none_constant(self):        self.const.NONE = None        self.assertEqual(self.const.NONE, None)        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):            self.const.NONE = .211    def test_create_and_change_boolean_constant(self):        self.const.BOOLEAN = True        self.assertEqual(self.const.BOOLEAN, True)        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):            self.const.BOOLEAN = False    def 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 = 3212    def 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 = True    def 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 = True    def 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 = None    def 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 = None    def 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 = 1    def test_create_and_change_uuid_constant(self):        value = uuid.uuid4()        self.const.UUID = value        self.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.VERSION    def test_try_delete_undefined_const(self):        with self.assertRaisesRegexp(NameError, "name 'UNDEFINED' is not defined"):            del self.const.UNDEFINED    def test_get_all_defined_constants(self):        self.assertDictEqual(self.const(), {})        self.const.A = 1        self.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 -aLinux 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 constantCONSTANT = 'hello'# put constant in numpy and make read onlyCONSTANT = 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/exceptnew_value = 'goodbye'try:    CONSTANT[0] = new_valueexcept:    print "cannot change CONSTANT to '%s' it's value '%s' is immutable" % (        new_value, CONSTANT[0])# attempt to modify our constant producing ValueErrorCONSTANT[0] = new_value>>>CONSTANT hellocannot change CONSTANT to 'goodbye' it's value 'hello' is immutableTraceback (most recent call last):  File "shuffle_test.py", line 15, in 
CONSTANT[0] = new_valueValueError: assignment destination is read-only

当然,这仅保护numpy的内容,而不保护变量“ CONSTANT”本身; 您仍然可以:

CONSTANT = 'foo'

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

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

CONSTANT = [1,2,3]

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


#17楼

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

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)如果我们想在实例级别使用常量,则:

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 "
", line 1, in
ValueError: You can't change a constant

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

# metaclass of my class Fooclass FooMeta(type): pass# class Fooclass Foo(metaclass=FooMeta): pass# I create constants in my metaclassFooMeta.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):    @property    def name(self):        return "John"

您可以看一下以找到更多使用Python属性的方法。


#19楼

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

只需定义空类。

例如:

class RED:     passclass 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 collectionsimport itertoolsdef 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.OneOne>>> print myConstants.TwoTwo>>> print myConstants.ThreeFour>>> myConstants.One = 'Two'Traceback (most recent call last):  File "
", line 1, in
AttributeError: can't set attribute

#23楼

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

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.

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

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

简单胜于复杂。

实用性胜过纯度。


#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库会为您提供帮助( )。

$ pip install pconst

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

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


#30楼

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

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

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}

转载地址:http://woogj.baihongyu.com/

你可能感兴趣的文章
shell 脚本读取文件内容并输出--问题总结(编码问题)
查看>>
2016-2018年第九届蓝桥杯【C++省赛B组】【题目汇总】
查看>>
《用TCP/IP进行网际互联 第一卷:原理,协议与结构》1、概述 2、底层网络技术 3、网际互联的概念和结构模型
查看>>
VMware Workstation虚拟机提示:锁定文件失败,打不开磁盘“****”或它所依赖的某个快照磁盘,模块“Disk”启动失败的解决办法
查看>>
AttributeError: module ‘matplotlib‘ has no attribute ‘verbose‘
查看>>
\OBJ\FreeRTOS.axf: Error: L6218E: Undefined symbol xTaskGetSchedulerState (referred from delay.o).
查看>>
FreeRTOS.axf: Error: L6200E: Symbol SysTick_Handler multiply defined (by port.o and delay.o).
查看>>
java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries.
查看>>
Permission denied: user=dr.who, access=READ_EXECUTE, inode="/usr":root:supergroup:drwx------
查看>>
IDEA中配置spring出现URI is not registered (Settings | Languages & Frameworks | Schemas and DTDs)
查看>>
Spark从kafka中读取数据,Direct Approach相较于Receiver-based Approach方式的区别
查看>>
安装VMware-tools出现错误:Error: Unable to find the binary installation directory(answer BINDIR)
查看>>
Linux切换到用户目录
查看>>
关于web项目下jar包的放置问题
查看>>
IDEA打war包方法
查看>>
SQL明明写对了,为什么还是报错
查看>>
@ConfigurationProperties的prefix的值别直接用user
查看>>
CSDN刚换图标了?
查看>>
java.sql.SQLException: Access denied for user ‘‘@‘125.71.195.131‘ (using password: YES)
查看>>
yml文件不提示,如何解决?
查看>>