`final` ключевое слово для переменных в Python? - PullRequest
45 голосов
/ 29 апреля 2009

Я не смог найти документацию по эквиваленту Java final в Python, есть такая вещь?

Я создаю снимок объекта (используется для восстановления, если что-то не получается); как только эта переменная резервной копии назначена, ее не следует изменять - для этого будет полезна функция, похожая на финальную в Python.

Ответы [ 9 ]

63 голосов
/ 29 апреля 2009

В Python нет `` окончательного '' эквивалента.

Но для создания доступных только для чтения полей экземпляров классов можно использовать свойство .

Редактировать : возможно, вы хотите что-то вроде этого:

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

        self.__dict__[attr] = value
56 голосов
/ 29 апреля 2009

Наличие переменной в Java, равное 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
}

Итак, ваш вопрос о том, существует ли final в Python. Это не так.

Однако в Python есть неизменные структуры данных. Например, хотя вы можете изменить list, вы не можете изменить tuple. Вы можете изменить set, но не frozenset и т. Д.

Я бы посоветовал не беспокоиться о принудительном применении немутации на уровне языка и просто сосредоточиться на том, чтобы убедиться, что вы не пишете код, который изменяет эти объекты после их назначения.

9 голосов
/ 29 апреля 2009

Переменная "назначить один раз" является проблемой проектирования. Вы разрабатываете свое приложение так, что переменная устанавливается один раз и только один раз.

Однако, если вам нужна проверка вашего проекта во время выполнения, вы можете сделать это с помощью оболочки вокруг объекта.

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

Это неуклюжий, но он обнаружит проблемы проектирования во время выполнения.

7 голосов
/ 29 апреля 2009

Нет такой вещи. В целом отношение Python звучит так: «Если вы не хотите, чтобы это изменилось, просто не изменяйте его». Клиенты API вряд ли будут в любом случае просто копаться в ваших недокументированных внутренностях.

Вы могли бы, я полагаю, обойти это, используя кортежи или именованные кортежи для соответствующих битов вашей модели, которые по своей природе неизменны. Это по-прежнему не помогает с любой частью вашей модели, которая, конечно, должна быть изменчивой.

6 голосов
/ 29 апреля 2009

Python не имеет эквивалента "final". Он также не имеет "public" и "protected", кроме как по соглашению об именах. Это не та «зависимость и дисциплина».

5 голосов
/ 30 июня 2009

вы можете смоделировать что-то подобное через протокол дескриптора , поскольку он позволяет определять чтение и установку переменной так, как вы хотите.

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
3 голосов
/ 29 апреля 2009

http://code.activestate.com/recipes/576527/ определяет функцию замораживания, хотя она не работает идеально.

Я бы подумал просто оставить его изменчивым.

0 голосов
/ 10 августа 2018

У Python действительно нет окончательного типа, у него есть неизменяемые типы, такие как кортежи, но это нечто другое.

Некоторые другие ответы здесь делают классы полными псевдо-финальными переменными, и я предпочитаю, чтобы в моем классе было только несколько типов 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 голосов
/ 07 сентября 2013

Хотя это старый вопрос, я решил добавить еще одну потенциальную опцию: вы также можете использовать assert, чтобы проверить, что переменная установлена ​​на то, что вы изначально предполагали установить - двойная проверка, если вы будете , Хотя это не то же самое, что final в Java, его можно использовать для создания аналогичного эффекта:

PI = 3.14
radius = 3

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

Как видно выше, если бы PI по какой-то причине не было установлено на 3.14, то было бы выброшено AssertionError, поэтому блок try/except, вероятно, был бы мудрым дополнением. В любом случае, это может пригодиться в зависимости от вашей ситуации.

...