我在Python中找不到相当于Java final
的文档,有这样的事吗?
我正在创建一个对象的快照(如果有任何失败则用于恢复);一旦分配了这个备份变量,就不应该修改它 - Python中的类似最终功能对此很有用。
答案 0 :(得分:63)
Python中没有“最终”等价物。
但是,要创建类实例的只读字段,可以使用property函数。
编辑:也许你想要这样的东西:
class WriteOnceReadWhenever:
def __setattr__(self, attr, value):
if hasattr(self, attr):
raise Exception("Attempting to alter read-only value")
self.__dict__[attr] = value
答案 1 :(得分:56)
在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确实有不可变的数据结构。例如,虽然您可以改变list
,但您无法改变tuple
。您可以改变set
而不是frozenset
等
我的建议是不要担心在语言层面强制执行非变异,而只是集中精力确保在分配这些对象后不要编写任何改变这些对象的代码。
答案 2 :(得分:9)
一次性赋值变量是一个设计问题。您可以设置应用程序,使变量只设置一次。
但是,如果您想要对设计进行运行时检查,可以使用对象周围的包装器来完成。
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
这很笨重,但它会在运行时检测到设计问题。
答案 3 :(得分:7)
没有这样的事情。一般来说,Python的态度是“如果你不想修改它,就不要修改它”。无论如何,API的客户都不太可能只是在你的无证内部进行攻击。
我想,你可以通过使用元组或命名元组来处理模型的相关位,这本身就是不可变的。对于你的模型的任何部分来说,这仍然没有帮助,当然必须是可变的。
答案 4 :(得分:6)
Python没有“最终”的等价物。除了命名约定外,它也没有“公共”和“受保护”。这不是“束缚和纪律”。
答案 5 :(得分:6)
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__
答案 6 :(得分:5)
您可以通过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
答案 7 :(得分:3)
http://code.activestate.com/recipes/576527/定义了一个冻结函数,虽然它不能很好地工作。
我会考虑让它变得可变。
答案 8 :(得分:3)
截至2019年和PEP 591,Python的类型为Final
。在Python 3.8发行之前,它在标准库中不可用,但是在此之前,您可以通过typing-extensions库使用它。尽管Python仍然是一种动态类型的语言,但它不会像final
在Java中那样起作用。但是,如果将它与mypy之类的静态类型检查器一起使用,它将为您带来非常相似的好处。
还有一个final
装饰器,可用于将类方法标记为final并防止被覆盖。同样,这仅在“编译时”进行检查,因此您需要在工作流程中包括静态类型检查器。
答案 9 :(得分:0)
虽然这是一个老问题,但我想我还会添加另一个可能的选项:您还可以使用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
,因此try/except
块可能是明智的补充。无论如何,根据您的情况,它可能会派上用场。
答案 10 :(得分:0)
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"