【问题标题】:Constant instance variables?常量实例变量?
【发布时间】:2010-12-04 09:15:22
【问题描述】:

我使用@property 来确保对对象实例变量的更改由我需要的方法包装。

当一个实例有一个逻辑上不应该改变的变量时怎么办?例如,如果我正在为 Process 创建一个类,则每个 Process 实例都应该有一个 PID 属性,该属性将经常被访问但不应更改。

处理试图修改该实例变量的人的最 Pythonic 方式是什么?

  • 只相信用户不要尝试改变 他们不应该做的事情?

  • 使用属性但引发 如果实例变量是异常 改变了吗?

  • 还有别的吗?

【问题讨论】:

标签: python properties instance setter instance-variables


【解决方案1】:

在变量名前加上__,并创建只读属性,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

【讨论】:

  • 最后两行的意思是“f.foo”和“f.foo='baz'”,对吧?
  • 我发现名称混乱的“私有”属性比它们的价值更麻烦。一个下划线将使子类化更容易,同时仍向用户传达“不要碰这个”。
  • 未损坏名称的问题是它们可能会在子类中被意外覆盖。由于这些字段不是您的公共 API 的一部分,因此不应要求 API 客户端知道您的“私有”字段的名称,但无论如何他们都必须这样做,因为否则它们可能会破坏您的类。当然,如果在新版本的类中引入一个新字段,您可以破坏现有客户端,这些客户端的子类已经使用相同的字段名称。 Mangled 版本仍然存在所有这些问题,但它确实降低了很多可能性。
【解决方案2】:

简单地信任用户并不一定是坏事;如果你只是编写一个快速的 Python 程序,只用一次就扔掉,你很可能只是相信用户不会改变 pid 字段。

恕我直言,强制只读字段的最 Pythonic 方式是使用在尝试设置字段时引发异常的属性。

所以,恕我直言,您对这些东西有很好的直觉。

【讨论】:

    【解决方案3】:

    也许你可以覆盖__setattr__?在行中,

    def __setattr__(self, name, value):
        if self.__dict__.has_key(name):
            raise TypeError, 'value is read only'
        self.__dict__[name] = value
    

    【讨论】:

      【解决方案4】:

      只需使用一个属性和一个隐藏属性(以 one 下划线为前缀)。

      简单的属性是只读的!

      >>> 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 为例,它必须非常小心!

      如果您只想隐藏属性,请使用单个下划线。如您所见,无需添加额外的魔法——如果您不定义 set 函数,则您的属性与方法的返回值一样是只读的。

      【讨论】:

        猜你喜欢
        • 2014-10-18
        • 2014-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多