web-dev-qa-db-ja.com

Pythonの変数に相当する `final`キーワード?

PythonでJavaのfinalに相当するものに関するドキュメントが見つかりませんでした。そのようなことはありますか?

オブジェクトのスナップショットを作成しています(何かが失敗した場合の復元に使用されます)。このバックアップ変数が割り当てられたら、変更しないでください-Pythonの最後のような機能はこのために良いでしょう。

48
Jason Coon

Java be finalに変数があるということは、基本的に変数に割り当てたら、その変数を別のオブジェクトを指すように再割り当てできないことを意味します。オブジェクトを変更することはできません。たとえば、次のJavaコードは完全に機能します。

public final List<String> messages = new LinkedList<String>();

public void addMessage()
{
    messages.add("Hello World!");  // this mutates the messages list
}

しかし、以下はコンパイルすらしません:

public final List<String> messages = new LinkedList<String>();

public void changeMessages()
{
    messages = new ArrayList<String>();  // can't change a final variable
}

あなたの質問は、Pythonにfinalが存在するかどうかです。ありません。

ただし、Pythonには不変のデータ構造があります。たとえば、listを変更することはできますが、Tupleを変更することはできません。 set、ただしfrozensetなどではない.

私のアドバイスは、言語レベルで非変異を強制することを心配せず、割り当てられた後にこれらのオブジェクトを変異させるコードを書かないようにすることに集中することです。

58
Eli Courtwright

Pythonには「最終」に相当するものはありません。

ただし、クラスインスタンスの読み取り専用フィールドを作成するには、 property 関数を使用できます。

Edit:おそらく次のようなものが欲しいでしょう:

class WriteOnceReadWhenever:
    def __setattr__(self, attr, value):
        if hasattr(self, attr):
            raise Exception("Attempting to alter read-only value")

        self.__dict__[attr] = value
64
Stephan202

1回割り当て変数は設計上の問題です。変数が一度だけ設定されるようにアプリケーションを設計します。

ただし、設計の実行時チェックが必要な場合は、オブジェクトのラッパーを使用して実行できます。

class OnePingOnlyPleaseVassily( object ):
    def __init__( self ):
        self.value= None
    def set( self, value ):
        if self.value is not None:
            raise Exception( "Already set.")
        self.value= value

someStateMemo= OnePingOnlyPleaseVassily()
someStateMemo.set( aValue ) # works
someStateMemo.set( aValue ) # fails

それは不格好ですが、実行時に設計上の問題を検出します。

9
S.Lott

そのようなことはない。一般に、Python態度は「これを変更したくない場合は、変更しないでください」です。APIのクライアントは、とにかくドキュメント化されていない内部構造をただぶらぶらすることはほとんどありません。

本質的に不変であるモデルの関連ビットにタプルまたは名前付きタプルを使用することで、これを回避できると思います。もちろん、それはもちろん、変更可能でなければならないモデルのどの部分にも役立ちません。

7
millimoose

Pythonには「最終」に相当するものはありません。命名規則を除き、「パブリック」と「保護」もありません。それはその「束縛と規律」ではありません。

6
RichieHindle

descriptor protocol を使用して、そのような何かをシミュレートできます。これは、変数の読み取りと設定を希望どおりに定義できるためです。

class Foo(object):

  @property
  def myvar(self):
     # return value here

  @myvar.setter
  def myvar(self, newvalue):
     # do nothing if some condition is met

a = Foo()
print a.myvar
a.myvar = 5 # does nothing if you don't want to
5
UncleZeiv

http://code.activestate.com/recipes/576527/ はフリーズ機能を定義しますが、完全には機能しません。

しかし、それを変更可能のままにすることを検討します。

3
cobbal

これは古い質問ですが、さらに別の潜在的なオプションを追加することを考えました:assertを使用して、変数が最初に設定されたものに設定されていることを確認することもできます。これはJavaのfinalとは異なりますが、同様の効果を作成するために使用できます。

PI = 3.14
radius = 3

try:
    assert PI == 3.14
    print PI * radius**2
except AssertionError:
    print "Yikes."

上記のように、何らかの理由でPI3.14に設定されていない場合、AssertionErrorがスローされるため、try/exceptブロックはおそらく賢明な追加です。とにかく、あなたの状況に応じて便利になるかもしれません。

0
John the King

Pythonには確かにfinal型はありません。タプルなどの不変型がありますが、それは別のものです。

ここの他の回答のいくつかは、クラスを疑似最終変数でいっぱいにしますが、私のクラスにはいくつかのFinal型しか持たないので、記述子を使用して最終型を作成することをお勧めします:

from typing import TypeVar, Generic, Type

T = TypeVar('T')

class FinalProperty(Generic[T]):
    def __init__(self, value: T):
        self.__value = value
    def __get__(self, instance: Type, owner) -> T:
        return self.__value
    def __set__(self, instance: Type, value: T) -> None:
        raise ValueError("Final types can't be set")

このクラスを次のように使用する場合:

class SomeJob:
    FAILED = FinalProperty[str]("Failed")

そうすると、そのクラスのどのインスタンスでもその変数を設定できなくなります。残念ながら、WriteOnceReadWheneverの回答と同様に、クラス変数を設定できます。

job = SomeJob()
job.FAILED = "Error, this will trigger the ValueError"
SomeJob.FAILED = "However this still works and breaks the protection afterwards"
0
user2799096

2019および PEP 591 の時点で、PythonにはFinalタイプがあります。 Python 3.8のリリースまで標準ライブラリでは使用できませんが、それまでは、type-extensionsライブラリを介して使用できます。 Javaは依然として動的に型付けされた言語ですが、Pythonの最終的な作品としては機能しません。しかし、 mypy のような静的型チェッカーと一緒に使用すると、非常によく似た利点が得られます。

クラスメソッドをfinalとしてマークし、オーバーライドされないようにするために適用できるfinalデコレータもあります。繰り返しますが、これは「コンパイル時」にのみチェックされるため、ワークフローに静的型チェッカーを含める必要があります。

0
antonagestam