Как мне создать константу в Python? - PullRequest
846 голосов
/ 21 апреля 2010

Есть ли способ объявить константу в Python? В Java мы можем создавать постоянные значения следующим образом:

public static final String CONST_NAME = "Name";

Что эквивалентно приведенному выше объявлению константы Java в Python?

Ответы [ 33 ]

2 голосов
/ 14 декабря 2017

В Python константы не существуют. Но вы можете указать, что переменная является константой и не должна изменяться, добавив CONST_ или CONSTANT_ в начало имени переменной или присвоив имя переменной в BLOCK CAPITALS и указав, что она является константой в комментарии:

    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.
2 голосов
/ 27 ноября 2017

Вы можете сделать это с collections.namedtuple и itertools:

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
2 голосов
/ 30 сентября 2017

Вы можете использовать StringVar или IntVar и т. Д., Ваша константа равна const_val

val = 'Stackoverflow'
const_val = StringVar(val)
const.trace('w', reverse)

def reverse(*args):
    const_val.set(val)
2 голосов
/ 06 сентября 2018

(Этот абзац должен был стать комментарием к этим ответам здесь и там , в которых упоминается namedtuple, но он становится слишком длинным, чтобы помещаться в комментарии Итак, вот и все.)

Упомянутый выше подход namedtuple является определенно инновационным. Однако для полноты в конце раздела NamedTuple его официальной документации написано:

перечисляемые константы могут быть реализованы с именованными кортежами, но проще и эффективнее использовать простое объявление класса:

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

Другими словами, официальная документация предпочитает использовать практический способ, а не фактически реализовывать поведение только для чтения. Я думаю, это станет еще одним примером Zen of Python :

Простое лучше, чем сложное.

практичность превосходит чистоту.

2 голосов
/ 11 августа 2017

Вот хитрость, если вам нужны константы и их значения не имеют:

Просто определите пустые классы.

например:

class RED: 
    pass
class BLUE: 
    pass
2 голосов
/ 23 июля 2018

Нет идеального способа сделать это. Насколько я понимаю, большинство программистов просто используют заглавные буквы для идентификатора, поэтому PI = 3.142 может быть легко понята как константа.

С другой стороны, если вы хотите что-то, что действительно действует как константа, я не уверен, что вы найдете это. Что бы вы ни делали, всегда найдется способ отредактировать «константу», чтобы она не была константой. Вот очень простой грязный пример:

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.

На самом деле все, что нужно кому-то, чтобы изменить значение, это:

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

Это то же самое для всех других решений, которые вы найдете здесь - даже самые умные, которые создают класс и переопределяют метод set attribute - всегда будут обходить их. Вот как выглядит Python.

Моя рекомендация - просто избегать хлопот и просто использовать ваши идентификаторы. На самом деле это не будет правильной константой, но опять же ничего не будет.

1 голос
/ 01 апреля 2017

Вы можете заключить константу в массив 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 изменится, однако это быстро вызовет ошибку TypeError при первом вызове CONSTANT[0] в скрипте.

хотя ... я полагаю, если вы когда-нибудь изменили его на

CONSTANT = [1,2,3]

теперь вы больше не получите TypeError. хммм ....

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

1 голос
/ 23 декабря 2015

Я пишу утилиту lib для python const: 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 url: pypi или github

1 голос
/ 25 февраля 2015

В моем случае мне понадобились неизменяемые байтовые массивы для реализации криптографической библиотеки, содержащей много литеральных чисел, которые я хотел обеспечить постоянными.

Этот ответ работает, но попытка переназначения элементов bytearray не вызывает ошибку.

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 "<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')

Более мощный, простой и, возможно, даже более «питонический» подход предполагает использование объектов вида памяти (буферные объекты в <= python-2.6). </p>

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)

Назначение элемента 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
0 голосов
/ 30 января 2019

Из всех приведенных здесь ответов самый простой способ создать постоянную переменную в Python. Просто сделайте кортеж одного измерения.

myconstant_var = (10,)

Вот и все. Теперь переменная myconstant_var не может быть изменена

...