wake-up-neo.net

`final`-Schlüsselwort für Variablen in Python?

Ich konnte keine Dokumentation zu einem Äquivalent von Javas final in Python finden. Gibt es so etwas?

Ich erstelle eine Momentaufnahme eines Objekts (wird zur Wiederherstellung verwendet, wenn etwas fehlschlägt). Wenn diese Sicherungsvariable einmal zugewiesen ist, sollte sie nicht mehr geändert werden. Eine abschließende Funktion in Python wäre dafür Nizza.

42
Jason Coon

Wenn eine Variable in Java final ist, bedeutet dies im Wesentlichen, dass Sie diese Variable nach dem Zuweisen einer Variablen nicht erneut zuweisen können, um auf ein anderes Objekt zu zeigen. Das bedeutet nicht, dass das Objekt nicht geändert werden kann. Der folgende Java-Code funktioniert beispielsweise einwandfrei:

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

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

aber Folgendes würde nicht einmal kompilieren:

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

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

Ihre Frage ist also, ob in Python final vorhanden ist. Es tut nicht.

Python hat jedoch unveränderliche Datenstrukturen. Während Sie beispielsweise eine list mutieren können, können Sie eine Tuple nicht mutieren. Sie können eine set aber keine frozenset mutieren, usw.

Mein Rat wäre, sich keine Sorgen zu machen, keine Nicht-Mutation auf Sprachebene durchzusetzen, und sich einfach darauf zu konzentrieren, dass Sie keinen Code schreiben, der diese Objekte nach ihrer Zuweisung mutiert.

52
Eli Courtwright

In Python gibt es keine Entsprechung.

Um schreibgeschützte Felder von Klasseninstanzen zu erstellen, können Sie jedoch die Funktion property verwenden.

Edit: Vielleicht möchten Sie so etwas wie:

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

        self.__dict__[attr] = value
60
Stephan202

Eine einmal zuordenbare Variable ist ein Entwurfsproblem. Sie gestalten Ihre Anwendung so, dass die Variable nur einmal festgelegt wird.

Wenn Sie jedoch eine Laufzeitüberprüfung Ihres Designs durchführen möchten, können Sie dies mit einem Wrapper um das Objekt tun.

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

Das ist klobig, aber zur Laufzeit werden Konstruktionsprobleme erkannt.

9
S.Lott

Es gibt keine solche Sache. Im Allgemeinen lautet die Python-Einstellung "Wenn Sie dies nicht modifiziert haben möchten, ändern Sie es einfach nicht". Es ist unwahrscheinlich, dass Clients einer API ohnehin nur Ihre undokumentierten Interna durchspielen.

Sie könnten dies umgehen, indem Sie Tupel oder Nameduples für die relevanten Bits Ihres Modells verwenden, die von Natur aus unveränderlich sind. Das hilft natürlich noch bei keinem Teil Ihres Modells, der natürlich veränderbar sein muss.

7
millimoose

Python hat kein Äquivalent von "final". Es gibt auch nicht "public" und "protected", außer durch Namenskonvention. Es ist nicht diese "Knechtschaft und Disziplin".

6
RichieHindle

sie können so etwas über das descriptor-Protokoll simulieren, da Sie damit das Lesen und Setzen einer Variablen wie gewünscht definieren können.

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/ definiert eine Freeze-Funktion, die jedoch nicht einwandfrei funktioniert.

Ich würde es jedoch in Betracht ziehen, es einfach veränderbar zu lassen.

3
cobbal

Obwohl dies eine alte Frage ist, habe ich mir gedacht, dass ich noch eine weitere mögliche Option hinzufügen würde: Sie können auch assert verwenden, um zu überprüfen, ob eine Variable auf das gesetzt ist, was Sie ursprünglich beabsichtigt haben - eine doppelte Überprüfung, wenn Sie möchten. Obwohl dies nicht dasselbe ist wie final in Java, kann es verwendet werden, um einen ähnlichen Effekt zu erzeugen:

PI = 3.14
radius = 3

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

Wenn PI aus irgendeinem Grund nicht auf 3.14 gesetzt wäre, würde eine AssertionError ausgelöst werden, so dass ein try/except-Block wahrscheinlich eine sinnvolle Ergänzung wäre. Unabhängig davon kann es abhängig von Ihrer Situation nützlich sein.

0
John the King

Python hat in der Tat keinen endgültigen Typ, es hat unveränderliche Typen wie Tupel, aber das ist etwas anderes.

Einige der anderen Antworten hier machen Klassen voll mit endgültigen Pseudo-Variablen. Ich ziehe vor, dass meine Klasse nur wenige Final-Typen enthält. Ich empfehle daher, einen Deskriptor zu verwenden, um den finalen Typ zu erstellen:

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

Wenn Sie diese Klasse wie folgt verwenden:

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

Dann können Sie diese Variable in keiner Instanz dieser Klasse festlegen .. Leider können Sie die Klassenvariable wie bei der Antwort von WriteOnceRead immer festlegen.

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

Ab 2019 und PEP 591 hat Python den Typ Final. Es wird in der Standardbibliothek erst mit der Veröffentlichung von Python 3.8 verfügbar sein, aber bis dahin können Sie es über die Typing-Extensions-Bibliothek verwenden. Es wird nicht als endgültiges Werk in Java funktionieren, obwohl Python immer noch eine dynamisch typisierte Sprache ist. Aber wenn Sie es zusammen mit einer statischen Typprüfung wie mypy verwenden, erhalten Sie sehr ähnliche Vorteile.

Es gibt auch einen final -Dekorator, der angewendet werden kann, um Klassenmethoden als endgültig zu kennzeichnen und zu verhindern, dass sie überschrieben werden. Auch dies wurde nur zur "Kompilierungszeit" überprüft, sodass Sie eine statische Typprüfung in Ihren Workflow aufnehmen müssen.

0
antonagestam