web-dev-qa-db-fra.com

Mot-clé `final` équivalent pour les variables en Python?

Je ne pouvais pas trouver de documentation sur un équivalent de la final de Java en Python, existe-t-il une telle chose?

Je crée un instantané d'un objet (utilisé pour la restauration si quelque chose échoue); une fois que cette variable de sauvegarde est affectée, elle ne doit plus être modifiée - une fonctionnalité de type final en Python serait agréable pour cela.

42
Jason Coon

Le fait qu'une variable en Java soit final signifie en gros qu'une fois que vous avez affecté une variable, vous ne pouvez pas réaffecter cette variable pour qu'elle pointe vers un autre objet. En réalité, cela ne signifie pas que l'objet ne peut pas être modifié. Par exemple, le code Java suivant fonctionne parfaitement:

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

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

mais ce qui suit ne compilerait même pas:

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

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

Votre question est donc de savoir si final existe en Python. Ce ne est pas.

Cependant, Python a des structures de données immuables. Par exemple, vous pouvez muter une list, mais vous ne pouvez pas muter une Tuple. Vous pouvez muter une set mais pas une frozenset, etc.

Mon conseil serait de ne pas vous soucier de l'application de la non-mutation au niveau de la langue et de simplement vous assurer que vous n'écriviez aucun code qui mue ces objets après leur affectation.

52
Eli Courtwright

Il n’existe pas d’équivalent «final» en Python.

Toutefois, pour créer des champs d'instances de classe en lecture seule, vous pouvez utiliser la fonction property .

Edit: vous voulez peut-être quelque chose comme ça:

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

Une variable assignée une fois est un problème de conception. Vous concevez votre application de manière à ce que la variable soit définie une fois et une fois seulement.

Toutefois, si vous souhaitez vérifier votre conception au moment de l'exécution, vous pouvez le faire avec un wrapper autour de l'objet.

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

C'est maladroit, mais cela détectera les problèmes de conception au moment de l'exécution.

9
S.Lott

Il n'y a pas une telle chose. En général, l'attitude de Python est la suivante "si vous ne voulez pas que cela soit modifié, ne le modifiez pas". De toute façon, il est peu probable que les clients d’une API se contentent de fouiller autour de vos composants internes non documentés.

Je suppose que vous pourriez contourner ce problème en utilisant des tuples ou des tuples nommés pour les éléments pertinents de votre modèle, qui sont par nature immuables. Cela n’aide toujours pas les parties de votre modèle qui doivent bien sûr être modifiables.

7
millimoose

Python n'a pas d'équivalent de "final". Il n'a pas non plus "public" et "protégé", sauf par convention de nommage. Ce n'est pas cela "esclavage et discipline".

6
RichieHindle

vous pouvez simuler quelque chose comme ça avec le descriptor protocol , puisqu'il permet de définir la lecture et de définir une variable comme vous le souhaitez.

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/ définit une fonction de gel, même si cela ne fonctionne pas parfaitement.

Je considérerais simplement le laisser mutable cependant.

3
cobbal

Bien qu'il s'agisse d'une vieille question, j'ai pensé ajouter encore une autre option potentielle: vous pouvez également utiliser assert pour vérifier qu'une variable est définie sur celle à laquelle vous souhaitiez initialement qu'elle soit définie - une double vérification si vous voulez. Bien que ce ne soit pas la même chose que final en Java, cela peut être utilisé pour créer un effet similaire:

PI = 3.14
radius = 3

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

Comme indiqué ci-dessus, si PI n'était pas défini sur 3.14 pour une raison quelconque, un AssertionError serait lancé, de sorte qu'un bloc try/except serait probablement un ajout judicieux. Quoi qu'il en soit, cela peut s'avérer utile selon votre situation.

0
John the King

Python n’a en effet pas de type final, il a des types immuables tels que les n-uplets mais c’est autre chose.

Certaines des autres réponses ici font des classes pleines de pseudo-variables finales et je préfère que ma classe n'ait que quelques types Final, je suggère donc d'utiliser un descripteur pour créer le type 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")

Si vous utilisez cette classe comme ceci:

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

Dans ce cas, vous ne pourrez définir cette variable dans aucune instance de cette classe . Malheureusement, comme dans le cas de WriteOnceReadWever, vous pouvez toujours définir la variable de classe, même si vous répondez.

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