我在 Python 中找不到与 Java 等效的文档final
,有这样的东西吗?
我正在创建一个对象的快照(如果出现任何故障,用于恢复);一旦分配了此备份变量,就不应对其进行修改——Python 中的类似 final 的功能对此会很好。
在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
}
所以你的问题是关于 Python 中是否final
存在。它不是。
但是,Python 确实具有不可变的数据结构。例如,虽然您可以改变 a list
,但不能改变 a tuple
。您可以改变 aset
但不能改变 afrozenset
等。
我的建议是不要担心在语言级别强制执行非变异,而只需专注于确保您不会编写任何代码在分配这些对象后对其进行变异。
final
Python 中没有等价物。
但是,要创建类实例的只读字段,您可以使用属性函数。
编辑:也许你想要这样的东西:
class WriteOnceReadWhenever:
def __setattr__(self, attr, value):
if hasattr(self, attr):
raise Exception("Attempting to alter read-only value")
self.__dict__[attr] = value
Python 3.8(通过PEP 591)添加了Final
变量、函数、方法和类。以下是一些使用它的方法:
@final
装饰器(类、方法)
from typing import final
@final
class Base:
# Cannot inherit from Base
class Base:
@final
def foo(self):
# Cannot override foo in subclass
Final
注解
from typing import Final
PI: Final[float] = 3.14159 # Cannot set PI to another value
KM_IN_MILES: Final = 0.621371 # Type annotation is optional
class Foo:
def __init__(self):
self.bar: Final = "baz" # Final instance attributes only allowed in __init__
请注意,与其他类型提示一样,这些提示不会阻止您覆盖类型,但它们确实有助于 linter 或 IDE 警告您有关不正确的类型使用。
一次赋值变量是一个设计问题。您设计应用程序的方式是只设置一次变量。
但是,如果您想要对您的设计进行运行时检查,您可以使用对象周围的包装器来完成。
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
这很笨重,但它会在运行时检测设计问题。
哪有这回事。总的来说,Python 的态度是“如果你不想修改,就不要修改它”。无论如何,API 的客户不太可能只是在您未记录的内部结构中闲逛。
我想,您可以通过对模型的相关位使用元组或命名元组来解决此问题,这些位本质上是不可变的。当然,这仍然无助于模型中必须可变的任何部分。
Python 没有“final”的等价物。除了命名约定外,它也没有“公共”和“受保护”。这不是那种“束缚和纪律”。
您可以通过描述符协议模拟类似的东西,因为它允许以您希望的方式定义读取和设置变量。
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
http://code.activestate.com/recipes/576527/定义了一个冻结功能,虽然它不能完美地工作。
不过,我会考虑让它保持可变。
Python 确实没有最终类型,它确实具有不可变类型,例如元组,但那是另一回事。
这里的其他一些答案使类充满了伪最终变量,我更喜欢我的类只有几个最终类型,所以我建议使用描述符来创建最终类型:
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"
虽然这是一个老问题,但我想我会添加另一个可能的选项:您还可以使用assert
来验证变量是否设置为您最初打算设置的内容 - 如果您愿意,请仔细检查。虽然这与 Java 中的不一样final
,但它可以用来创建类似的效果:
PI = 3.14
radius = 3
try:
assert PI == 3.14
print PI * radius**2
except AssertionError:
print "Yikes."
如上所示,如果PI
由于某种原因未设置为3.14
,AssertionError
则会抛出 an ,因此try/except
块可能是明智的添加。无论如何,根据您的情况,它可能会派上用场。