Pythonで定数を作成するにはどうすればよいですか?


991

Pythonで定数を宣言する方法はありますか?Javaでは、次の方法で定数値を作成できます。

public static final String CONST_NAME = "Name";

上記のPythonでのJava定数宣言に相当するものは何ですか?


6
実際には、読み取り専用変数を作成する方法は、pythonのプロパティ function / decoratorを介して可能です。inv答えは、そのカスタム使用の例です。プロパティはそれよりも汎用的ですが、それがどのように機能するかについての優れた分析は、Shalabh ChaturvediのPython Attributes and Methodsにあります。
n611x007 14

20
私見、不変性の強制は「Pythonicではない」。Python 2.7 True=Falseでは、書き込みを行ってから(2+2==4)==True返すこともできますFalse
osa

8
他の回答が示唆するように、定数を宣言する方法や必要はありません。しかし、あなたは慣習についてこのPEPを読むかもしれません。例:THIS_IS_A_CONSTANT
Perera

34
@osa:Python 3ではできません- SyntaxError: can't assign to keyword。これは良いことのようです。
naught101

3
これは今まで言及されていなかったことに驚いていますが、列挙型定数を定義するにはEnumsが良い方法のように思えます。
cs95

回答:


973

いいえ、ありません。Pythonでは、変数または値を定数として宣言することはできません。変更しないでください。

クラスにいる場合、同等のものは次のようになります。

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
次に、「Pythonの定数」にあることを行うのではなく、「プロパティ」関数またはデコレータを使用する必要があります。
セスジョンソン

26
人々はPerlの同じ機能について質問します。「定数を使用」というインポートモジュールがありますが、(AFAIK)は、値を返す小さな関数を作成するための単なるラッパーです。Pythonでも同じです。例:def MY_CONST_VALUE(): return 123
kevinarpe

8
"いいえ、ありません。" 確かに、しかし他の人の作業に基づいて、Python 2.7の「定数」(「列挙型」を欠いている)の短くて単純な実装を使用して、はるか下に回答を追加しました。これらは列挙型のような読み取り専用name.attributeであり、任意の値を含めることができます。宣言は簡単ですNums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0)。使用方法は簡単です。print 10 + Nums.PI結果を変更しようとすると、例外Nums.PI = 22=> ValueError(..)になります。
ToolmakerSteve、

110
変更しないでください。あなたは私の日を作った
Hi-Angel

89
「変更しないでください」はまったく役に立ちません。それは質問に答えません、そして私はそれが削除されることを提案します。
Bartek Banachewicz 2016年

354

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

CONST = _Const()

print CONST.FOO
##3131964110

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

コードの説明:

  1. 式を受け取る関数constantを定義し、それを使用して「getter」(式の値のみを返す関数)を作成します。
  2. セッター関数は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を定義するために、もみは2つの関数(fset、fget-名前は私の好みです)を定義します。
  2. 次に、組み込みproperty関数を使用して、「設定」または「取得」できるオブジェクトを作成します。
  3. property関数の最初の2つのパラメーターの名前はfsetおよびであることに注意してくださいfget
  4. 独自のゲッターとセッターにこれらの名前を選択したという事実を使用し、そのスコープのすべてのローカル定義に適用される**(ダブルアスタリスク)を使用してキーワード辞書を作成し、property関数にパラメーターを渡します

11
AttributeErrorおよびのドキュメントに基づいTypeErrorて、発生した例外は新しいエラーであると思います。ConstantErrorこれは、ネーミングまたはそのようなものを提案するもので、のサブクラスですTypeErrordocs.python.org/2/library/exceptions.html
ArtOfWarfare

3
私はこのコードに驚いています。FOO()およびBAR()メソッドのフォントが引数としてselfを持っているのはなぜですか?私のIDEは、赤の括弧に下線を引きます(「コンパイル」エラー)。自分を入れるのに疲れましたが、エラーが発生しました。
user3770060 2016

10
これらの長さに行くことは、Python言語の明らかな欠陥を概説しています。これをPython 3に追加する必要性を感じなかったのはなぜですか。誰もそれを提案したとは信じられず、いくつかの委員会の背後にある論理が定数ではないのがわかりません。いや。」
Andrew S

8
そして、あなたのソリューションは、CONST.__dict__['FOO'] = 7
次のコマンド

11
@OscarSmith、「自己文書化コード」の設計を改善すると思います。一部の値を変更できないことをコードに明示すると、すべてのソースコードを読み取って、一部の値が変更されないことに気付くよりも理解しやすくなります。また、誰かが定数であるはずの値を変更する可能性をブロックします。覚えておいてください:明示的は暗黙的より優れています。
ガブリエル

112

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

18
実行してdef MY_CONSTANT(): return "one"も、後でコードで実行するMY_CONSTANT = "two"(または関数を再宣言する)誰かを停止することはありません。
マシュー・シンケル2013年

6
@MatthewSchinckelそれは慣習についてです。また、MY_CONSTANTを変更しても使用法MY_CONSTANT()は変更されませんが、エラーがスローされます。Pythonでは、何かを変更できる場合、巧妙なトリックで保護することはできません。
Anurag Uniyal 2013年

3
namedtupleアプローチをご利用いただきありがとうございます。間違いなく革新的です。また、ここに私の「コメント」が関連しているかもしれません。
RayLuo 2018

@MatthewSchinckelはpythonで何でも再定義できるので、それは本当に良い点ではありません。
cslotty

@MatthewSchinckelアイデアはを書くことMY_CONSTANT = MY_CONSTANT()ではなくMY_CONSTANT()、定数として使用することです。もちろん、これ。しかし、これは問題なく、Pythonの原則「私たちはすべてここでは大人です」に非常に一致しています。つまり、開発者は、正当な理由があり、何をしているのかを知っているときにルールをオーバーライドすることを決定することをほとんど禁じられません。
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変数を設定する試みを阻止できます。必要に応じて、ここで例外をスローできます。クラス名でインスタンスをインスタンス化すると、クラス経由で直接アクセスできなくなります。

それは1つの値にとっては完全な苦痛ですが、CONSTオブジェクトに多くをアタッチすることができます。上流階級がいるので、クラス名も少し不器用に見えますが、全体的にはかなり簡潔だと思います。


11
これは「メカニズム」は最小限ですが、機能性が最も高いため、最良かつ最も明確な答えです。ただし、例外を発生させることは重要です...オプションではありません。
Erik Aronesty

意味のあるエラーを自動的に生成する短いルートを作成しましたが、ほとんど同じスタイルです。ここでは、比較のために元のアイデアを残しました。
ジョンベッツ

このCONST.接頭辞がまだ必要なのは残念です。また、マルチモジュールの状況では、これは複雑になります。
Alfe、

1
たいていの場合、その状況ではとにかく定数をいくつかの関連するバンドルにグループ化したいと思うと思います(1つの巨大なCONSTオブジェクトではなく)。
ジョンベッツ

なぜこの答えはまだそれほど遠いのですか?__slots__解決策はとてもエレガントかつ効果的です。私が読んだすべてから、これはPythonで定数を作成することとほぼ同じです。どうもありがとうございました。そして興味のある人のために、ここでは__slots__魔法の見事で詳細な説明があります。
JohnGalt

34

Pythonには定数がありません。

おそらく最も簡単な代替策は、そのための関数を定義することです。

def MY_CONSTANT():
    return 42

MY_CONSTANT() 定数のすべての機能(およびいくつかの迷惑な中括弧)が追加されました。


1
私はこの提案を追加したかっただけですが、幸運にも私は評価の低い回答までスクロールダウンしました。私はそれがさらに支持されることを望みます、そしてそれが定数のすべての機能を持ち、それが非常にシンプルで簡単であることに完全に同意します。すべての洗練されたソリューションの定型コードの量を見ると、中かっこは比較的煩わしくありません。
yaccob 2017年

1
これは最も簡単な答えですが、多少のオーバーヘッドがあり、ばか者が戻り値を変更するのを止めないことに注意してください。これにより、コードがソースを変更することを防ぐことができます
MrMesees '10年

@MrMeseesが戻り値を変更しますか?ソースを編集するということですか?しかし、これから、定数(などconstexpr)が実際のハード定数であるC ++でも保護されません。
ルスラン

@Ruslanは、Pythonにはconstexprがないため、編集された値が外部コンテキストに返された後も停止しないことを意味していました。この例では、凍結状態を強制するために42に対して何も行われていません。
MrMesees

20

上位2つの回答(大文字の名前を持つ変数を使用するか、プロパティを使用して値を読み取り専用にする)に加えて、名前付き定数を実装するためにメタクラスを使用することが可能であることを述べておきます。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ですが、非常に使いやすく便利です。(このモジュールには、定数が読み取り専用であることなど、いくつかの機能があります。READMEを参照してください。)

さまざまなリポジトリに浮かぶ同様のソリューションがありますが、私の知る限りでは、定数から期待される基本的な機能の1つが不足している(定数である、任意のタイプであるなど)か、難解な機能が追加されていますそれらをあまり一般的ではないものにします。しかし、YMMV、フィードバックに感謝します。:-)


3
GitHubでの実装よりも気に入っています。逆引き参照機能を実装する基本的なクラスを作成する準備がほぼ整いましたが、あなたはそれ以上のことをしたようです!
Kerr

ありがとう、@カー、それは私が得て私を幸せにした最初のフィードバックです。:-)
hans_meine 2013年

驚くばかり。私はこれを試しました。これをオプションとして用意しておくと便利です。私が読み取り専用の側面を十分に気にするかどうかは決定していませんが、単に行うのではなく、これを使用するようにしますdef enum(**enums): return type('Enum', (), enums)Numbers = enum(ONE=1, TWO=2, THREE='three')stackoverflow.com / a / 1695250/199364のセクション「以前のバージョンでは...」
ToolmakerSteve

19

プロパティは定数を作成する1つの方法です。getterプロパティを宣言し、setterを無視することでそれを行うことができます。例えば:

class MyFinalProperty(object):

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

私が書いた記事を見て Pythonプロパティを使用する他の方法を見つけることができます。


貴重なソリューションの下。このページ(この回答ではない)を見つけた後、これを実装しました。まだ追加されていない場合は、丸で囲んで追加しました。この回答の有用性を強調したかったのです。
マルク

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の「定数」)を効果的に作成できます。回避策が進むにつれ、それは一種のエレガントです。(より洗練されたアプローチは、単純にPython言語を改善することです---どのような言語で再定義することができますmath.piか--余談ですが。)

(これを書いているときに、namedtupleについて言及したこの質問への別の答えがわかりましたが、namedを作成する必要がないため、Javaで期待する構文により近い構文を示すため、ここで続けます。タイプあなたがする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型を必要としないことです(「匿名の名前付きタプル」はoxymoronのように聞こえますが)いい_Fooので、できれば名前付きタプルに名前を付けますモジュールのインポートにエスケープします。

ここで2番目のポイントは、名前タプルのインスタンスすぐに作成して呼び出すことFooです。別の手順でこれを行う必要はありません(必要な場合を除きます)。これで、Javaで実行できることを実行できます。

>>> Foo.CONST_NAME
'Name'

ただし、それに割り当てることはできません。

>>> Foo.CONST_NAME = 'bar'

AttributeError: can't set attribute

謝辞:名前付きタプルアプローチを発明したと思いましたが、他の誰かが同様の(コンパクトではありませんが)答えを出したことがわかりました。次に、Pythonの「名前付きタプル」とは何ですか。は、これsys.version_infoが現在名前付きタプルであることを示しているため、おそらくPython標準ライブラリがすでにこのアイデアをはるかに早く考案しているでしょう。

残念ながら(これはPythonのままです)、Foo割り当て全体を完全に削除できます。

>>> Foo = 'bar'

(フェイスパーム)

しかし、少なくとも私たちはFoo.CONST_NAME値が変更されるのを防ぎます。それは何もないよりはましです。幸運を。


namedtupleアプローチをご利用いただきありがとうございます。間違いなく革新的です。また、ここに私の「コメント」が関連しているかもしれません。
RayLuo 2018

10

PEP 591には「最終」修飾子があります。施行は型チェッカー次第です。

だからあなたはできる:

MY_CONSTANT: Final = 12407

注: FinalキーワードはPython 3.8バージョンにのみ適用されます


9

以下は、読み取り専用(定数)属性を持つインスタンスを作成する「定数」クラスの実装です。たとえば、Nums.PIとして初期化された値を取得するために使用でき、例外3.14159Nums.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です。

そして、__ setattr__をオーバーライドするアイデアのための@Raufioの回答に感謝します。

または、より多くの機能を備えた実装については、GitHub@Hans_meinenamed_constantsを参照してください


2
Pythonは同意する大人の言語です。このようなものに対する保護はありません。Nums._d['PI'] = 22 言語自体は、物を非可変としてマークする方法を提供していないと私は信じています。
Ajay M

8

タプルは、値の1つを変更しようとするとエラーが発生するため、技術的には定数として修飾されます。1つの値を持つタプルを宣言する場合は、次のように、唯一の値の後にコンマを配置します。

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

この変数の値を確認するには、次のようなものを使用します。

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

この値を変更しようとすると、エラーが発生します。


7

__setattr__基本オブジェクトクラスのメソッドをオーバーライドするクラスを作成し、それで定数をラップします。Python2.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を表示し、定数を使用して操作を実行していることを確認することをお勧めします(ただし、最も「Python的な」方法ではないかもしれません)。


興味深いアプローチの+1。すでに提供されている回答ほどきれいではありませんが。そして、以前に提案された最も単純なソリューションでさえ、この回答よりもdef ONE(): return 1使いやすいです。ONE()ONE.value
ToolmakerSteve

7

残念ながら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 -> 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

「定数」を宣言するPythonの方法は、基本的にモジュールレベルの変数です。

RED = 1
GREEN = 2
BLUE = 3

次に、クラスまたは関数を記述します。定数はほとんど常に整数であり、Pythonでも不変であるため、変更される可能性はほとんどありません。

もちろん、明示的に設定しない限りRED = 2


21
はい。ただし、「明示的に設定」する機能をブロックすることRED = 2は、(他の言語では)変数名を「定数」として宣言できるという全体的な利点です!
ToolmakerSteve

6
あなたはそれをブロックすることから利益を得ますか?constについて最も役立つのは、通常はコンパイラーの最適化ですが、これは実際にはPythonではありません。一定のものにしたいですか?変更しないでください。他の誰かがそれを変更することを心配している場合は、それを彼らの範囲外に置くか、誰かがそれを変更している場合、それは彼らの問題であり、あなたではなく、彼らがそれに対処する必要があることに気づくだけです。
ケビン

@Kevin:「メリットはありますか?」、staticクラスのすべてのインスタンスの値に対して単一のストレージを持つことの利点は?静的/クラス変数を実際に宣言する可能性がない限り。
2017

8
根本的な問題は、それを変更できない真理の源である値と見なし、マジック値(Pythonでよく見られる)を導入する代わりに、コード全体でそれを真実の源として使用することです。 -そして、他の人はそれを彼らが自由に変更することを許可されているものとして見るかもしれません。誰かがグローバル変数を変更し、それがどこで変更されたのかわからない場合、「red」ではなくRED = "blue"が原因でアプリケーションがクラッシュすると、完全に不要な問題が発生し、すでに非常に簡単に解決されています。普遍的に理解されています。
ダグルームズ17/10/30

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

Python辞書は可変であるため、定数を宣言するのに適した方法とは思えません。

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

Pythonでは、定数はすべて大文字の名前を持つ変数であり、単語はアンダースコア文字で区切られています。

例えば

DAYS_IN_WEEK = 7

値は変更可能であるため、変更可能です。しかし、名前の規則があなたに一定であると言っているので、なぜあなたはそうするのですか?結局、それはあなたのプログラムです!

これは、Python全体で採用されているアプローチです。private同じ理由でキーワードはありません。名前の前にアンダースコアを付けると、プライベートにすることを目的としています。プログラマーがプライベートキーワードを削除できるのと同じように、コードはルールに違反する可能性があります。

Pythonはconstキーワードを追加することもできますが、プログラマーはキーワードを削除し、必要に応じて定数を変更できますが、なぜそれを行うのでしょうか。ルールを破る場合は、とにかくルールを変更できます。しかし、名前が意図を明確にした場合、なぜわざわざルールを破る必要があるのでしょうか。

たぶん、値に変更を適用することが理にかなっているユニットテストがあるでしょうか?実世界では週の日数を変更できない場合でも、週に8日何が起こるかを確認します。言語が例外を作るのを止めた場合、この1つのケースだけがあり、ルールを破る必要があります。それでも、アプリケーションで定数であっても、定数として宣言することをやめる必要があります。これが変更された場合にどうなるかを確認するこの1つのテストケースだけです。

すべて大文字の名前は、定数であることを示しています。それが重要です。とにかく変更する力があるコードに制約を強制する言語ではありません。

それがパイソンの哲学です。


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

これは、ここにある他のすべてのソリューションと同じです。クラスを作成し、属性設定メソッドを再定義する賢いソリューションでさえ、常に回避策があります。それがまさにPythonです。

私の推奨は、すべての面倒を回避し、識別子を大文字にすることです。それは実際には適切な定数ではありませんが、再び何もしません。


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)

この正確なアプローチにより、定数に名前空間を付けることができます。


これを読んでいるすべての人にとって、これらの定数の1つとして可変オブジェクトを設定すると、誰でもその内部値を変更できることに注意してください。たとえば、bar = [1、2、3]とすると、次のように実行できます。CONSTS.bar [1] = 'a'これは拒否されません。これに注意してください。
ファンイグナシオサンチェス

楽しみのために作ったこのハッキーな方法の代わりに、代わりにPythonのプロパティデコレータを使用することをお勧めします。
ファンイグナシオサンチェス

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

(この段落は、それらの答えにコメントすることを意図して、ここそこに言及した、namedtupleが、それはそう、ここではそれが行く、コメントの中にフィットするように長すぎるなっています。)

上記の名前付きタプルのアプローチは、間違いなく革新的です。ただし、完全を期すために、公式ドキュメントの NamedTupleセクションの最後に次のように記載されています。

列挙定数は名前付きタプルで実装できますが、単純なクラス宣言を使用する方が簡単で効率的です。

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

言い換えると、公式のドキュメントは、実際には読み取り専用の動作を実装するのではなく、実用的な方法を使用することを好むのです。Zen of Pythonのもう1つの例になると思います。

シンプルは複雑よりも優れています。

実用性は純粋さを上回ります。


2

これは、すでに利用可能な回答のいくつかを改善するために私が作成したイディオムのコレクションです。

私は定数の使用がpythonicではないことを知っています、そしてあなたは家でこれをするべきではありません!

しかし、Pythonはそのような動的言語です!このフォーラムは、定数のように見えて感じられる構造の作成がどのように可能であるかを示しています。この答えは、言語で何が表現できるかを探ることを主な目的としています。

私に厳しすぎないでください:-)。

詳細については、これらのイディオムについての伴奏ブログを書きました。

この投稿では、定数変数を値への定数参照(不変またはその他)に呼び出します。さらに、クライアントコードがその値を更新できない可変オブジェクトを参照するとき、変数は固定値を持っていると言います。

定数のスペース(SpaceConstants)

このイディオムは、定数変数(別名SpaceConstants)の名前空間のようなものを作成します。これは、モジュールオブジェクトの使用を回避するためのAlex Martelliによるコードスニペットの変更です。具体的には、理由の中、私はクラスファクトリを呼んでこの変更が使用SpaceConstantsの機能は、と呼ばれるクラスSpaceConstantsが定義されており、そのインスタンスが返されます。

私は、ポリシーベースのデザインそっくりでPythonで実装するクラスファクトリの使用を検討しstackoverflowのもでブログ投稿を

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の変更です。この実装は、setattr関数とgetattr関数の間で共有クロージャーと呼んでいるものを利用しています。変更可能なオブジェクトの値は、関数共有クロージャー内の変数キャッシュ定義によってコピーおよび参照されます。これは、可変オブジェクトのクロージャ保護コピーと呼ばれるものを形成します

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の不変の名前空間です。それはで上空シンプルジョン・ベッツ答えの組み合わせであるのStackOverflowクラスファクトリ

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

Pythonでは定数は存在しませんが、変数が定数であり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

私の場合、私が定数であることを保証したい多くのリテラル数を含む暗号ライブラリの実装のために不変のバイト配列が必要でした。

この回答は機能しますが、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')

よりパワフルでシンプル、そしておそらくもっと「パイソン的な」アプローチは、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

私は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 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変化するであろう、しかしそれはすぐに最初の時間はTypeError例外をスローう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.