常量实例变量?

9 投票
4 回答
5500 浏览
提问于 2025-04-15 14:51

我使用 @property 来确保对对象实例变量的修改都通过我需要的方法来进行。

那么,当一个实例有一个逻辑上不应该被改变的变量时该怎么办呢?比如说,如果我在创建一个表示进程的类,每个进程实例应该有一个 PID 属性,这个属性经常会被访问,但不应该被修改。

处理有人试图修改这个实例变量的情况,最符合 Python 风格的方法是什么呢?

  • 就简单信任用户,不去改变他们不该改的东西吗?

  • 使用属性,但如果实例变量被修改就抛出一个异常吗?

  • 还有其他方法吗?

4 个回答

1

简单来说,使用一个属性和一个隐藏的属性(前面加一个下划线)就可以了。

简单的属性是只读的,也就是说你不能修改它!

>>> class Test (object):
...  @property
...  def bar(self):
...   return self._bar
... 
>>> t = Test()
>>> t._bar = 2
>>> t.bar
2
>>> t.bar = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

用两个下划线来隐藏属性并不是为了隐藏实现细节,而是为了确保你不会和子类的属性发生冲突;比如说,如果你在使用混入(mixin),就需要特别小心!

如果你只是想隐藏这个属性,可以用一个下划线。正如你所看到的,没有什么额外的魔法需要添加——如果你不定义一个设置函数,你的属性就和一个方法的返回值一样,只能读取,不能修改。

3

简单地信任用户并不一定是坏事;如果你只是写一个一次性使用的快速Python程序,那么你可以放心地相信用户不会去改动pid字段。

在我看来,最符合Python风格的做法是使用一个属性,当有人试图修改这个字段时,就抛出一个异常。

所以,我觉得你对这些事情的直觉是很不错的。

9

在变量名前加上__,然后创建一个只读属性,Python会自动处理异常,这样变量就能防止被意外覆盖。

class foo(object):
    def __init__(self, bar):
        self.__bar = bar

    @property
    def bar(self):
        return self.__bar

f = foo('bar')
f.bar         # => bar
f.bar = 'baz' # AttributeError; would have to use f._foo__bar

撰写回答