在Python中,如何创建不可重新赋值的属性(类似于Java中的`final`标记)?

93 投票
12 回答
106900 浏览
提问于 2025-04-15 11:18

在Python中,有没有类似于Java中的final关键字的东西?也就是说,能不能在创建类的实例后,禁止对某个特定属性进行赋值?我在文档里没找到相关的内容。

我正在创建一个对象的快照(如果出现问题可以用来恢复);一旦这个备份变量被赋值,就不应该再被修改——在Python中如果有类似final的功能就好了。

12 个回答

72

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__

请注意,像其他类型提示一样,这些并不会阻止你覆盖类型,但它们可以帮助代码检查工具或开发环境提醒你关于不正确的类型使用。

76

在Python中没有和final完全相同的东西。如果你想创建一些只读的类实例字段,可以使用property函数,或者你可以像下面这样做:

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开始有一个@typing.final的用法(正如Cerno提到的),但这并不会在运行时真正让值变成final

73

在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(冻结集合),等等。

我的建议是,不用太担心语言层面上强制不修改这些对象,主要是确保你在给这些对象赋值后,不再写任何会修改它们的代码。

撰写回答