파이썬에서 상수를 어떻게 만듭니 까?


988

파이썬에서 상수를 선언하는 방법이 있습니까? Java에서는 다음과 같은 방법으로 상수 값을 만들 수 있습니다.

public static final String CONST_NAME = "Name";

파이썬에서 위의 Java 상수 선언에 해당하는 것은 무엇입니까?


6
실제로 읽기 전용 변수 를 만드는 방법 은 파이썬의 속성 함수 / 데코레이터 를 통해 가능합니다 . inv대답 은 그 사용자 정의 사용법의 예입니다. 속성은 그보다 일반적으로 사용되지만 Shalabh Chaturvedi의 Python Attributes and Methods 에 대한 작동 방식에 대한 훌륭한 분석입니다 .
n611x007

20
불변성을 강요하는 IMHO는 "파이썬이 아닙니다". 파이썬 2.7에서는 심지어 쓰기 True=False(2+2==4)==True하고을 리턴 할 수도 있습니다 False.
osa

8
다른 답변에서 알 수 있듯이 상수를 선언 할 방법이 없거나 필요하지 않습니다. 그러나 협약에 관한 이 PEP 를 읽을 수 있습니다 . 예 : THIS_IS_A_CONSTANT
Rasika Perera

34
@ osa : 파이썬 3에서는 그렇게 할 수 없습니다 SyntaxError: can't assign to keyword. 이것은 좋은 것 같습니다.
naught101

3
지금까지 언급되지 않은 것에 놀랐지 만, 열거 형 은 열거 상수를 정의하는 좋은 방법처럼 보입니다.
cs95

답변:


973

아니 없어. 파이썬에서는 변수 나 값을 상수로 선언 할 수 없습니다. 변경하지 마십시오.

수업에 참여하는 경우 다음과 같습니다.

class Foo(object):
    CONST_NAME = "Name"

그렇지 않다면, 그것은 단지

CONST_NAME = "Name"

그러나 Alex Martelli의 Python 의 코드 스 니펫 상수를 살펴볼 수 있습니다 .


Python 3.8 typing.Final부터는 변수를 다시 할당해서는 안된다는 정적 유형 검사기 (mypy와 같은)를 알려주 는 변수 주석이 있습니다. 이것은 Java와 가장 가까운 것 final입니다. 그러나 실제로 재 할당을 막지는 않습니다 .

from typing import Final

a: Final = 1

# Executes fine, but mypy will report an error if you run mypy on this:
a = 2

27
"파이썬의 상수 (Constants in Python)"에있는 것을 수행하는 대신 "속성"함수 또는 데코레이터를 사용해야합니다.
세스 존슨

26
사람들은 Perl에서 동일한 기능에 대해 묻습니다. "상수 사용"이라는 가져 오기 모듈이 있지만 (AFAIK)는 값을 반환하는 작은 함수를 만드는 래퍼 일뿐입니다. 파이썬에서도 똑같이합니다. 예 :def MY_CONST_VALUE(): return 123
kevinarpe

8
"아니 없어." 사실, 다른 사람들의 작업을 바탕으로 파이썬 2.7 ( "enum"이 없음)에 대한 "Constants"를 짧고 간단하게 구현하여 아래에 답변을 추가했습니다. 이들은 열거 형 읽기 전용 name.attribute이며 모든 값을 포함 할 수 있습니다. 선언은 쉽고 Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0), 사용법은 간단 print 10 + Nums.PI합니다. 예외 Nums.PI = 22=> ValueError (..) 에서 결과를 변경하십시오 .
ToolmakerSteve

108
변경하지 마십시오. 당신은 내 하루를했다
Hi-Angel

89
"변경하지 마십시오"는 전혀 도움이되지 않습니다. 그것은 질문에 대답하지 않으며 제거 될 것을 제안합니다.
Bartek Banachewicz

354

더 없어 const다른 언어로 키워드, 그러나 재산권 만들 수 는 "게터 기능"이 데이터를 읽을 수있는,하지만 아니오 "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 0xDEADBEEF

CONST = _Const()

print CONST.FOO
##3131964110

CONST.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
##3131964110

CONST.FOO = 0
##Traceback (most recent call last):
##    ...
##    CONST.FOO = 0
##TypeError: None

@apply 데코레이터는 더 이상 사용되지 않는 것으로 보입니다.

  1. 식별자 FOO를 정의하기 위해 firs는 두 가지 함수를 정의합니다 (fset, fget-이름은 내가 선택했습니다).
  2. 그런 다음 내장 property함수를 사용하여 "설정"또는 "get"가능한 오브젝트를 구성하십시오.
  3. 참고 모자는 property함수의 처음 두 매개 변수의 이름은 fset하고 fget.
  4. 우리가 getter & setter에 대해 이러한 이름을 선택했다는 사실을 사용하고 매개 변수를 property함수에 전달하기 위해 해당 범위의 모든 로컬 정의에 ** (이중 별표)를 사용하여 키워드 사전을 만듭니다.

11
에 대한 설명서를 기반으로 AttributeError하고 TypeError, 나는 발생한 예외 내가 명명 할 것을 제안 새로운 오류가되어야한다고 생각 ConstantError또는 서브 클래스처럼 뭔가 TypeError. 만드는 문서의 섹션 나를 생각 : docs.python.org/2/library/exceptions.html
ArtOfWarfare

3
이 코드에 놀랐습니다. FOO () 및 BAR () 메서드 글꼴이 인수로 사용되는 이유는 무엇입니까? IDE가 빨간색으로 괄호 밑줄을 표시합니다 ( "컴파일"오류). 나는 그것을 넣는 데 피곤했지만 오류가 발생합니다.
user3770060

10
이 길이로 가면 파이썬 언어의 명확한 결함이 나타납니다. 왜 그들은 이것을 파이썬 3에 추가 할 필요가 없다고 생각 했습니까? 나는 아무도 그것을 제안하지 않았다는 것을 믿을 수 없으며 일부위원회의 논리를 볼 수 없습니다. 아. '
Andrew S

8
그리고 솔루션은 여전히 사용하여 결정 파이썬 프로그래머에 의해 수정 될 수있다CONST.__dict__['FOO'] = 7
pppery

11
@OscarSmith, '자체 문서화 된 코드'디자인을 향상시킬 것이라고 생각합니다. 일부 값을 변경할 수 없다는 코드를 코드에 명시하면 모든 소스 코드를 읽고 일부 값이 변경되지 않는다는 것을 이해하는 것보다 이해하기 쉽습니다. 또한 누군가가 일정 해야하는 값을 변경할 가능성을 차단합니다. 기억하십시오 : 명시 적은 암시 적보다 낫습니다.
Gabriel

112

파이썬은 무언가를 적용하는 언어 대신 __method개인 메소드와 _method보호 메소드에 대한 명명 규칙을 사용 합니다.

따라서 같은 방식으로 상수를 모든 대문자로 선언 할 수 있습니다.

MY_CONSTANT = "one"

이 상수가 절대 변경되지 않게하려면 속성 액세스에 연결하여 트릭을 수행 할 수 있지만 더 간단한 방법은 함수를 선언하는 것입니다.

def MY_CONSTANT():
    return "one"

문제는 어디에서나 MY_CONSTANT ()를 수행해야하지만 어디서나 MY_CONSTANT = "one"파이썬에서 올바른 방법입니다 (일반적으로).

명명 된 튜플 을 사용하여 상수를 만들 수도 있습니다 .

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

17
그렇게 def MY_CONSTANT(): return "one"해도 코드의 뒷부분에서 누군가를 멈추지 않을 것입니다 MY_CONSTANT = "two"(또는 기능 재 선언).
Matthew Schinckel

6
@ MatthewSchinckel 그것은 컨벤션에 관한 것이며, MY_CONSTANT를 변경하면 사용법 MY_CONSTANT ()는 변경되지 않지만 오류가 발생합니다.
Anurag Uniyal

3
명명 된 튜플 접근 방식을 가져 주셔서 감사합니다. 확실히 혁신적입니다. 내 "댓글" 과 관련 이있을 수도 있습니다 .
RayLuo

@ MatthewSchinckel 파이썬에서 모든 것을 재정의 할 수 있으므로 실제로는 좋은 지적이 아닙니다.
cslotty

@MatthewSchinckel 아이디어는 쓰지 않고 상수 MY_CONSTANT = MY_CONSTANT()로 사용 MY_CONSTANT()하는 것입니다. 물론입니다. 그러나 이것은 훌륭하고 파이썬 원칙 "우리는 모두 성인입니다"와 매우 유사합니다. 즉, 개발자가 정당한 이유가 있고 규칙을 무시하고 결정을 내리는 것을 거의 금지 하지 않습니다 .
jonathan.scholbach

69

최근에 의미있는 오류 메시지를 자동으로 발생시키고 __dict__다음을 통한 액세스를 방지하는 매우 간결한 업데이트를 발견했습니다 .

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'

우리는 스스로를 인스턴스로 만들고 슬롯을 사용하여 추가 속성을 추가 할 수 없도록 정의합니다. 또한 __dict__액세스 경로가 제거 됩니다. 물론 전체 개체를 여전히 재정의 할 수 있습니다.

편집-원래 솔루션

아마도 여기에 트릭이 누락되었지만 이것이 나를 위해 작동하는 것 같습니다.

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

인스턴스를 생성하면 매직 __setattr__메소드가 FOO변수 설정을 시도하고 가로 챌 수 있습니다. 원한다면 여기에서 예외를 던질 수 있습니다. 클래스 이름으로 인스턴스를 인스턴스화하면 클래스를 통해 직접 액세스 할 수 없습니다.

하나의 가치에 대한 총 고통이지만 CONST객체 에 많은 것을 붙일 수 있습니다 . 상류층이 있으면 클래스 이름도 약간 거칠어 보이지만 전체적으로 간결하다고 생각합니다.


11
"메커니즘"이 가장 적지 만 기능이 가장 많기 때문에이 방법이 가장 명확하고 명확합니다. 옵션이 아니라 예외를 제기하는 것이 중요합니다.
Erik Aronesty

나는 의미있는 오류를 자동으로 생성하지만 같은 스타일을 가진 짧은 경로를 만들었습니다. 비교를 위해 원래 아이디어를 남겼습니다.
Jon Betts

CONST.접두사가 여전히 필요한 것이 유감입니다 . 또한 다중 모듈 상황에서 이것은 복잡해질 것입니다.
Alfe

1
필자는 일반적으로 하나의 거대한 CONST 객체가 아닌 해당 상황에서 상수를 관련 번들로 그룹화하려고한다고 생각하므로 그렇게 나쁘지는 않습니다.
존 베츠 19

왜이 답변이 여전히 아래에 있습니까?! __slots__솔루션은 매우 우아하고 효과적입니다. 내가 읽은 모든 것에서 이것은 파이썬에서 상수를 만드는 것과 거의 비슷합니다. 대단히 감사합니다. 그리고 관심있는 모든 사람을위한, 여기 의 화려한하고 깊이있는 설명이다 __slots__마술.
JohnGalt

34

파이썬에는 상수가 없습니다.

아마도 가장 쉬운 대안은 함수를 정의하는 것입니다.

def MY_CONSTANT():
    return 42

MY_CONSTANT() 이제 상수의 모든 기능을 갖추고 있습니다 (성가신 괄호).


1
방금이 제안을 추가하고 싶었지만 다행히도 저평가 답변으로 스크롤했습니다. 나는 그것이 더 많이지지되기를 희망하며 상수의 모든 기능을 가지고 있으며 매우 간단하고 간단하다는 것에 완전히 동의합니다. 모든 정교한 솔루션에서 상용구 코드의 양을 살펴보면 중괄호가 비교적 성가신 것으로 보입니다.
yaccob

1
이것은 가장 간단한 대답이지만 약간의 오버 헤드가 있으며 바보가 반환 값을 수정하는 것을 멈추지 않을 것입니다. 그것은 소스를 변경하는 코드를 더 아래로 내리는 것을 막을 것입니다.
MrMesees

@MrMes는 반환 값을 수정합니까? 소스 편집을 의미합니까? 그러나 이것으로부터 상수 (예 constexpr:)가 실제 하드 상수 인 C ++에서도 보호되지 않습니다 .
Ruslan

@Ruslan은 파이썬에 constexpr이 없으므로 외부 컨텍스트로 반환 된 후에 편집되는 값을 중지하지 않는다는 것입니다. 이 예에서 42 번의 동결 상태를 강제하는 것은 없습니다.
MrMesees

20

UPPERCASE 이름을 가진 변수를 사용하거나 속성을 사용하여 값을 읽기 전용으로 만드는 두 가지 최고의 답변 외에도 명명 된 상수 를 구현하기 위해 메타 클래스를 사용할 수 있다고 언급하고 싶습니다 . 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

이것은 약간 고급 파이썬이지만 여전히 사용하기 쉽고 편리합니다. (이 모듈에는 읽기 전용 상수를 포함하여 더 많은 기능이 있으며 README를 참조하십시오.)

다양한 저장소에 떠 다니는 비슷한 솔루션이 있지만, 내가 아는 한, 상수 (예 : 상수 또는 임의 유형)에서 기대할 수있는 기본 기능 중 하나가 부족하거나 밀교 기능이 추가되었습니다. 덜 일반적으로 적용하십시오. 그러나 YMMV, 피드백에 감사드립니다. :-)


3
GitHub에서 구현을 좋아합니다. 리버스 조회 기능을 구현 한 기본 클래스를 작성할 준비가 거의되었지만 그 이상을 수행 한 것으로 보입니다!
Kerr

감사합니다, @Kerr, 제가받은 첫 번째 피드백입니다. :-)
hans_meine

대박. 방금 시도했습니다. 이것을 옵션으로 사용하는 것이 좋습니다. 읽기 전용 측면에 대해 충분히 관심이 있는지 결정하지는 않았지만 단순히 수행하기보다는 이것을 사용하는 것이 좋습니다 def enum(**enums): return type('Enum', (), enums). Numbers = enum(ONE=1, TWO=2, THREE='three'), stackoverflow.com/a/1695250/199364에 따라 섹션 "이전 버전에서 ..."
ToolmakerSteve

19

속성은 상수를 만드는 한 가지 방법입니다. getter 속성을 선언하지만 setter를 무시하면됩니다. 예를 들면 다음과 같습니다.

class MyFinalProperty(object):

    @property
    def name(self):
        return "John"

파이썬 속성을 사용하는 더 많은 방법을 찾기 위해 작성한 기사를 살펴볼 수 있습니다 .


소중한 솔루션. 이 페이지 (이 답변이 아님)를 찾은 후에 이것을 구현하고 아직 추가하지 않은 경우 추가하여 다시 추가했습니다. 이 답변의 유용성을 강조하고 싶었습니다.
Marc

18

편집 : 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
# 1
my_const = MyConst()
my_const.A
# 1

MyConst.A = 'changed'
# TypeError
my_const.A = 'changed'
# TypeError

위의 예제는 다음과 같습니다 . 다음 은 Python 3 또 다른 예입니다.


10

명명 된 튜플을 임시 해결책으로 사용하여 Java의 정적 최종 변수 (Java "상수")와 동일한 방식으로 작동하는 상수를 효과적으로 작성할 수 있습니다. 해결 방법이 갈수록 우아합니다. (보다 우아한 접근 방식은 단순히 파이썬 언어를 개선하는 것입니다. --- 어떤 종류의 언어로 재정의 할 수 math.pi있습니까? – 그러나 난탈합니다.)

(이 글을 쓸 때 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유형이 필요하지 않다는 것입니다 ( "익명 튜플"은 옥시 모론처럼 들리더라도 좋을 것입니다). 그래서 우리는 namedtuple의 이름을 지정 _Foo하여 모듈 가져 오기로 빠져 나옵니다.

두 번째 요점은 우리가 즉시 nametuple 의 인스턴스만들어 호출한다는 것입니다 Foo. 별도의 단계에서이 작업을 수행 할 필요가 없습니다 (원하는 경우 제외). 이제 Java로 할 수있는 일을 할 수 있습니다 :

>>> Foo.CONST_NAME
'Name'

그러나 당신은 그것에 할당 할 수 없습니다 :

>>> Foo.CONST_NAME = 'bar'

AttributeError: can't set attribute

승인 : 나는 명명 된 튜플 접근법을 발명했다고 생각했지만 다른 사람이 비슷한 (작지는 않지만) 대답을 보았습니다. 그런 다음 파이썬에서 "명명 된 튜플"이란 무엇입니까? 이것은 sys.version_info이제 명명 된 튜플이므로 Python 표준 라이브러리는 이미이 아이디어를 훨씬 일찍 생각해 냈습니다.

불행히도 (여전히 파이썬 임) 전체 Foo과제를 모두 지울 수 있습니다 .

>>> Foo = 'bar'

(페이스 팜)

그러나 적어도 우리는 Foo.CONST_NAME가치가 변화 하는 것을 막고 있으며 , 그것은 아무것도 아닌 것보다 낫습니다. 행운을 빕니다.


명명 된 튜플 접근 방식을 가져 주셔서 감사합니다. 확실히 혁신적입니다. 내 "댓글" 과 관련 이있을 수도 있습니다 .
RayLuo

10

PEP 591 에는 '최종'한정자가 있습니다. 시행은 유형 검사기입니다.

그래서 당신은 할 수 있습니다 :

MY_CONSTANT: Final = 12407

참고 : Final 키워드는 Python 3.8 버전에만 적용됩니다


9

다음은 "Constants"클래스의 구현입니다.이 클래스는 읽기 전용 (일정한) 속성을 가진 인스턴스를 만듭니다. 예 사용할 수 있습니다 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

@MikeGraham의 FrozenDict 덕분에 시작점으로 사용되었습니다. Nums['ONE']사용법 구문 대신이 변경되었습니다 Nums.ONE.

그리고 @Raufio의 답변 덕분에 __ setattr __을 무시하는 아이디어가 있습니다.

또는 더 많은 기능을 갖춘 구현에 대해서는 GitHub@ Hans_meine 's named_constants를 참조하십시오.


2
파이썬은 동의하는 성인의 언어입니다. 이와 같은 것에 대한 보호는 없습니다. Nums._d['PI'] = 22 언어 자체는 변경 불가능한 것으로 표시하는 방법을 제공하지 않습니다.
Ajay M

8

튜플은 값 중 하나를 변경하려고하면 오류가 발생하므로 기술적으로 상수로 규정됩니다. 하나의 값으로 튜플을 선언하려면 다음과 같이 쉼표를 유일한 값 뒤에 넣으십시오.

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

이 변수의 값을 확인하려면 다음과 비슷한 것을 사용하십시오.

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

이 값을 변경하려고하면 오류가 발생합니다.


7

__setattr__기본 객체 클래스 의 메서드 를 재정의하는 클래스를 만들고 상수를 래핑합니다. 파이썬 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상수를 사용하여 작업을 수행하고 있음을 표시하고 알고 있는 것이 가장 좋습니다 (가장 '파이온적인'방법은 아님).


흥미로운 접근 방식으로 +1 이미 제공된 답변만큼 깨끗하지는 않지만. 그리고 가장 간단한 이전 제안 솔루션조차도이 답변보다 def ONE(): return 1사용하기 쉽습니다 . ONE()ONE.value
ToolmakerSteve

7

불행히도 파이썬에는 아직 상수가 없으며 수치 스럽습니다. ES6은 이미 모든 프로그래밍 언어에서 매우 유용한 기능이므로 JavaScript ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const ) 에 지원 상수를 추가 했습니다. 파이썬 커뮤니티의 다른 답변에서 대답했듯이 사용자 대문자 변수를 상수로 사용하지만 코드의 임의 오류를 방지하지는 않습니다. 원하는 경우 다음과 같이 단일 파일 솔루션이 유용 할 수 있습니다 (docstrings 사용법 참조).

파일 상수 .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 decimal
import uuid
import datetime
import unittest

from ..constants import Constant


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

사전을 명명 된 튜플로 자동 변환하여이 기능을 약간 개선 할 수 있습니다
Peter Schorn

6

"상수"를 선언하는 파이썬 방식은 기본적으로 모듈 수준 변수입니다.

RED = 1
GREEN = 2
BLUE = 3

그런 다음 클래스 나 함수를 작성하십시오. 상수는 거의 항상 정수이며 파이썬에서도 변경할 수 없으므로 변경할 가능성이 거의 없습니다.

물론 명시 적으로 설정하지 않는 한 RED = 2.


21
예, 그러나 "명시 적으로 설정 " 하는 기능을 차단 하면 RED = 2변수 이름을 "일정한"것으로 선언 할 수있는 이점이 있습니다 (다른 언어에서는).
ToolmakerSteve

6
당신이 그것을 차단함으로써 얻을 수 있습니까? const에 대한 가장 유용한 것은 보통 컴파일러 최적화가 아니며 실제로는 파이썬에서는 그렇지 않습니다. 일정한 것을 원하십니까? 변경하지 마십시오. 다른 사람이 그것을 바꾸는 것에 대해 걱정하고 있다면, 그것을 범위 바깥에 두거나 누군가가 그것을 바꾸면 그것이 문제이며 그들이 아니라 그것을 처리해야한다는 것을 깨달을 수 있습니다.
Kevin

@Kevin : " 겠습니까 이점은 당신이 ... 얻을 것 ,의 이익" static클래스의 모든 인스턴스의 값에 대한 하나의 저장을 가지고 있습니까? 정적 / 클래스 변수를 실제로 선언 할 가능성이 없다면.

8
근본적인 문제는 일부 사람들은 그것을 진리의 원천으로 볼 수 있으며, 변경할 수 없으며, 마법의 가치를 도입하는 대신 코드 전체에서 그것을 진리의 원천으로 사용할 수 있다는 것입니다 (파이썬에서 많이 볼 수 있습니다) -다른 사람들은 그것을 마음대로 바꿀 수있는 것으로 볼 수 있습니다. 누군가가 전역 변수를 변경하고 변수가 변경된 위치를 알 수없고 "빨간색"대신 RED = "blue"로 인해 응용 프로그램이 충돌하면 이미 간단하게 해결 된 완전히 불필요한 문제가 발생합니다. 보편적으로 이해됩니다.
Dagrooms

5

디스크립터 객체를 만들 수 있습니다.

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

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

4

파이썬 사전은 변경 가능하므로 상수를 선언하는 좋은 방법처럼 보이지 않습니다.

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

4

상수를 원하고 그 값을 신경 쓰지 않으면 트릭이 있습니다.

빈 클래스를 정의하십시오.

예 :

class RED: 
    pass
class BLUE: 
    pass

4

파이썬에서 상수는 단순히 모든 대문자로 된 이름을 가진 변수이며 단어는 밑줄 문자로 구분됩니다.

예 :

DAYS_IN_WEEK = 7

값을 변경할 수 있으므로 값을 변경할 수 있습니다. 그러나 이름에 대한 규칙이 당신에게 상수라고 말하면 왜 당신은 하시겠습니까? 결국, 그것은 당신의 프로그램입니다!

이것은 파이썬 전체에서 취하는 접근법입니다. 없습니다private같은 이유로 키워드 . 이름 앞에 밑줄을 붙이면 개인용이라는 것을 알 수 있습니다. 프로그래머가 비공개 키워드를 제거 할 수있는 것처럼 코드는 규칙을 어길 수 있습니다.

파이썬은 const 키워드를 있었지만 프로그래머는 키워드를 제거한 다음 원하는 경우 상수를 변경할 수 있지만 왜 그럴까요? 규칙을 어기려면 어쨌든 규칙을 변경할 수 있습니다. 그러나 이름이 의도를 분명히 밝히면 왜 규칙을 어 기지 않겠습니까?

가치에 변화를 적용하는 것이 적절한 단위 테스트가 있습니까? 실제 세계에서 일주일에 8 일 동안 어떤 일이 발생하는지 확인하기 위해 주중 일수를 변경할 수 없습니다. 이 경우에 언어가 예외를 만드는 것을 중단했다면 규칙을 어겨 야합니다 ... 그런 다음 응용 프로그램에서 상수이지만 상수로 선언하는 것을 중지해야합니다. 이 테스트 사례 만 변경되면 어떻게되는지 확인합니다.

모든 대문자 이름은 상수라는 것을 알려줍니다. 그것이 중요한 것입니다. 코드에 대한 언어 강제 제약이 아니므로 어쨌든 변경할 힘이 있습니다.

그것이 파이썬의 철학입니다.


4

완벽한 방법은 없습니다. 내가 이해하는 것처럼 대부분의 프로그래머는 식별자를 대문자로 사용하므로 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 속성 메소드를 재정의하는 영리한 솔루션조차도 여기에서 찾을 수있는 다른 모든 솔루션에 대해 동일합니다. 그것이 바로 파이썬입니다.

나는 모든 번거 로움을 피하고 식별자를 대문자로 사용하는 것이 좋습니다. 실제로 적절한 상수는 아니지만 다시는 아무것도하지 않습니다.


4

namedtuple로이를 수행하는 더 확실한 방법이 있습니다.

from collections import namedtuple


def make_consts(name, **kwargs):
    return namedtuple(name, kwargs.keys())(**kwargs)

사용 예

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

이 방법을 사용하면 상수 네임 스페이스를 만들 수 있습니다.


이 글을 읽는 모든 사람들에게, 가변 객체를 이러한 상수 중 하나로 설정하면 누구나 내부 값을 변경할 수 있습니다. 예를 들어 bar = [1, 2, 3]을 지정하면 다음과 같이 수행 할 수 있습니다. CONSTS.bar [1] = 'a'거부되지 않습니다. 따라서 이것에주의하십시오.
Juan Ignacio Sánchez

내가 재미로 만든이 해키 방법 대신 파이썬의 속성 데코레이터를 대신 사용하는 것이 좋습니다.
Juan Ignacio Sánchez

4

어쩌면 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.


3

StringVar 또는 IntVar 등을 사용할 수 있습니다. 상수는 const_val입니다.

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

def reverse(*args):
    const_val.set(val)

2

당신은 그것을 할 수 있습니다 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

2

(이 단락은 그 답변에 댓글로 의미되었다 여기거기에 언급,namedtuple 하지만 그래서 여기 간다 댓글에 맞는로 너무 오래지고 있습니다.)

위에서 언급 한 명명 된 튜플 방식은 확실히 혁신적입니다. 완전한 공식화를 위해 공식 문서 의 NamedTuple 섹션 끝에서 다음과 같이 읽습니다.

열거 형 상수는 명명 된 튜플로 구현할 수 있지만 간단한 클래스 선언을 사용하는 것이 더 간단하고 효율적입니다.

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

다시 말해서 공식 문서 종류는 실제로 읽기 전용 동작을 구현하는 대신 실용적인 방법을 사용하는 것을 선호합니다. 나는 그것이 Zen of Python 의 또 다른 예가 된 것 같습니다.

단순보다 복잡합니다.

실용성은 순도를 능가합니다.


2

다음은 이미 사용 가능한 답변 중 일부를 개선하기 위해 만든 숙어 모음입니다.

상수의 사용은 파이썬이 아니라는 것을 알고 집에서 이것을해서는 안됩니다!

그러나 파이썬은 역동적 인 언어입니다! 이 포럼은 상수처럼 보이고 느껴지는 구조를 만드는 방법을 보여줍니다. 이 답변은 언어로 표현할 수있는 것을 탐구하는 주요 목적으로 사용됩니다.

나에게 너무 가혹하지 마십시오 :-).

자세한 내용 은이 관용구에 대한 반주 블로그를 썼습니다 .

이 게시물에서는 상수 변수를 불변 또는 다른 값에 대한 상수 참조로 호출합니다. 또한 클라이언트 코드가 값을 업데이트 할 수없는 가변 객체를 참조 할 때 변수에 고정 값이 있다고 말합니다.

상수 공간 (SpaceConstants)

이 관용구는 상수 변수 (일명 SpaceConstants)의 네임 스페이스처럼 보이는 것을 만듭니다. 모듈 객체 사용을 피하기 위해 Alex Martelli 가 코드 스 니펫을 수정했습니다 . 특히,이 수정은 SpaceConstants 함수 내에서 SpaceConstants 라는 클래스 때문에 클래스 팩토리 라고 부르는 것을 사용합니다. 정의되고, 그것의 인스턴스가 반환됩니다.

나는 정책 기반 디자인 흡사 파이썬에서 구현하는 클래스 팩토리의 사용을 탐구 유래 와도에서 블로그 게시물을 .

def SpaceConstants():
    def setattr(self, name, value):
        if hasattr(self, name):
            raise AttributeError(
                "Cannot reassign members"
            )
        self.__dict__[name] = value
    cls = type('SpaceConstants', (), {
        '__setattr__': setattr
    })
    return cls()

sc = SpaceConstants()

print(sc.x) # raise "AttributeError: 'SpaceConstants' object has no attribute 'x'"
sc.x = 2 # bind attribute x
print(sc.x) # print "2"
sc.x = 3 # raise "AttributeError: Cannot reassign members"
sc.y = {'name': 'y', 'value': 2} # bind attribute y
print(sc.y) # print "{'name': 'y', 'value': 2}"
sc.y['name'] = 'yprime' # mutable object can be changed
print(sc.y) # print "{'name': 'yprime', 'value': 2}"
sc.y = {} # raise "AttributeError: Cannot reassign members"

고정 된 값의 공간 (SpaceFrozenValues)

이 다음 관용구는 참조 가능한 가변 객체가 고정되는 SpaceConstants 의 수정입니다 . 이 구현은 setattrgetattr 함수 사이에서 공유 클로저 라고 부르는 것을 활용 합니다. 가변 객체의 값은 함수 공유 클로저 내에서 변수 캐시 정의로 복사 및 참조됩니다 . 변경 가능한 객체의 폐쇄 보호 사본 이라고 부르는 것을 형성 합니다. .

getattr 은 깊은 복사를 수행하여 캐시의 값을 리턴 하므로이 관용구를 사용하는 데주의해야합니다 . 이 작업은 큰 개체에 상당한 성능 영향을 줄 수 있습니다!

from copy import deepcopy

def SpaceFrozenValues():
    cache = {}
    def setattr(self, name, value):
        nonlocal cache
        if name in cache:
            raise AttributeError(
                "Cannot reassign members"
            )
        cache[name] = deepcopy(value)
    def getattr(self, name):
        nonlocal cache
        if name not in cache:
            raise AttributeError(
                "Object has no attribute '{}'".format(name)
            )
        return deepcopy(cache[name])
    cls = type('SpaceFrozenValues', (),{
        '__getattr__': getattr,
        '__setattr__': setattr
    })
    return cls()

fv = SpaceFrozenValues()
print(fv.x) # AttributeError: Object has no attribute 'x'
fv.x = 2 # bind attribute x
print(fv.x) # print "2"
fv.x = 3 # raise "AttributeError: Cannot reassign members"
fv.y = {'name': 'y', 'value': 2} # bind attribute y
print(fv.y) # print "{'name': 'y', 'value': 2}"
fv.y['name'] = 'yprime' # you can try to change mutable objects
print(fv.y) # print "{'name': 'y', 'value': 2}"
fv.y = {} # raise "AttributeError: Cannot reassign members"

일정한 공간 (ConstantSpace)

이 관용구는 상수 변수 또는 ConstantSpace 의 불변 네임 스페이스입니다 . 그것은에서 놀랍도록 단순 존 베츠 '대답의 조합 에 유래 A를 클래스 공장 .

def ConstantSpace(**args):
    args['__slots__'] = ()
    cls = type('ConstantSpace', (), args)
    return cls()

cs = ConstantSpace(
    x = 2,
    y = {'name': 'y', 'value': 2}
)

print(cs.x) # print "2"
cs.x = 3 # raise "AttributeError: 'ConstantSpace' object attribute 'x' is read-only"
print(cs.y) # print "{'name': 'y', 'value': 2}"
cs.y['name'] = 'yprime' # mutable object can be changed
print(cs.y) # print "{'name': 'yprime', 'value': 2}"
cs.y = {} # raise "AttributeError: 'ConstantSpace' object attribute 'x' is read-only"
cs.z = 3 # raise "AttributeError: 'ConstantSpace' object has no attribute 'z'"

얼어 붙은 공간 (FrozenSpace)

이 관용구는 고정 된 변수 또는 FrozenSpace 의 불변 네임 스페이스입니다 . 생성 된 FrozenSpace 클래스를 닫아 각 변수를 보호 된 속성으로 만들어 이전 패턴에서 파생됩니다 .

from copy import deepcopy

def FreezeProperty(value):
    cache = deepcopy(value)
    return property(
        lambda self: deepcopy(cache)
    )

def FrozenSpace(**args):
    args = {k: FreezeProperty(v) for k, v in args.items()}
    args['__slots__'] = ()
    cls = type('FrozenSpace', (), args)
    return cls()

fs = FrozenSpace(
    x = 2,
    y = {'name': 'y', 'value': 2}
)

print(fs.x) # print "2"
fs.x = 3 # raise "AttributeError: 'FrozenSpace' object attribute 'x' is read-only"
print(fs.y) # print "{'name': 'y', 'value': 2}"
fs.y['name'] = 'yprime' # try to change mutable object
print(fs.y) # print "{'name': 'y', 'value': 2}"
fs.y = {} # raise "AttributeError: 'FrozenSpace' object attribute 'x' is read-only"
fs.z = 3 # raise "AttributeError: 'FrozenSpace' object has no attribute 'z'"

2

파이썬에서는 상수가 존재하지 않지만 변수가 상수라는 것을 나타낼 수 있습니다 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;

1

필자의 경우 상수를 유지하려는 많은 리터럴 숫자를 포함하는 암호화 라이브러리를 구현하려면 변경 불가능한 바이트 배열이 필요했습니다.

이 답변 은 효과가 있지만 바이트 배열 요소를 다시 할당하려고 시도해도 오류가 발생하지 않습니다.

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

보다 강력하고 단순하며 아마도 더 많은 '파이썬 (pythonic)'접근 방식은 memoryview 객체 (<= python-2.6의 버퍼 객체)를 사용합니다.

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

1

파이썬 const에 대한 util lib를 작성합니다 : kkconst-pypi support 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

numpy 배열에서 상수를 래핑하고 쓰기 전용 플래그를 지정할 수 있으며 항상 인덱스 0으로 호출 할 수 있습니다.

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

물론 이것은 변수 "CONSTANT"자체가 아니라 numpy의 내용 만 보호합니다. 당신은 여전히 ​​할 수 있습니다 :

CONSTANT = 'foo'

CONSTANT변경 것이다, 그러나 그것은 빠르게 형식 오류를 처음 던질 것CONSTANT[0] 나중에 스크립트에서 호출됩니다.

비록 ... 당신이 언젠가 그것을 바꾸었다면

CONSTANT = [1,2,3]

이제 더 이상 TypeError가 발생하지 않습니다. 흠 ...

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.