在__init__中使用python @property,给出了属性错误

时间:2011-10-26 20:11:43

标签: python properties

我的'修复'是正确/良好的练习方法吗?

我有一个Text()类,它会缓存它的表面以进行渲染,除非字体/大小发生变化。 (我从代码段中删除了字体属性)

如果我尝试在self.size中使用__init__,则会失败:

Traceback (most recent call last):
  File "temp.py", line 21, in <module>
    t = Text("arial", 6)
  File "temp.py", line 3, in __init__
    self.size = size
  File "temp.py", line 16, in size
    if self._size != px:            
AttributeError: 'Text' object has no attribute '_size'

我能够在self._text分配__init__,但我认为这是错误的,因为:

  1. 忽略可能有额外检查的setter
  2. 如果_text发生变化,
  3. 代码可能会中断,但如果使用的话,则可以正常 财产而不是。
  4. 错误代码:

    class Text(object):
        def __init__(self, font, size=12):
            self.size = size
            self.font = font
            self.dirty = False
    
        def draw(self):
            print "Draw: ", self.size, self.font, self.dirty
    
        @property
        def size(self): 
            return self._size
    
        @size.setter
        def size(self, px):
            if self._size != px:            
                self._size = px
                self.dirty=True
    
    if __name__  == "__main__":
        t = Text("arial", 6)
        t.draw()
        t.size = 8
        t.draw()
    

    我的修复:

    class Text(object):
        def __init__(self, font, size=12):
            self.size = size
            self.font = font
            self.dirty = False
    
        def draw(self):
            print "Draw: ", self.size, self.font, self.dirty
    
        @property
        def size(self): 
            return self._size
        @size.setter
        def size(self, px):
            try:
                if self._size != px:            
                    self._size = px
                    self.dirty=True
            except:
                self._size = 14
                self.dirty = True
    
    if __name__  == "__main__":
        t = Text("arial", 6)
        t.draw()
        t.size = 8
        t.draw()
    

2 个答案:

答案 0 :(得分:3)

   try:
        if self._size != px:            
            self._size = px
            self.dirty=True
    except:
        self._size = 14
        self.dirty = True

除了一个坏主意,因为你捕获所有异常。您可能会意外地捕获其他异常并忽略它。那将是个坏主意。 Python出于各种原因抛出异常,你最终会掩盖一个bug。出于同样的原因,您应该尽可能少地在try块中添加代码。

一种方法是:

try:
   size_changed = self._size != size
except AttributeError:
   size_changed = True

if size_changed:
    self._size = size
    self.dirty = True

但是解决这个问题的方法更简洁:

def __init__(self, font, size=12):
    # store something in the hidden attribute
    # so it will work as expected
    self._size = None

    self.size = size
    self.font = font
    self.dirty = False

答案 1 :(得分:2)

我使用的模式是:

class Text(object):
    def __init__(self, font, size=12):
        self.font = font
        self._size = size
        self.dirty = False
    @property
    def size(self):
        return self._size
    @size.setter
    def size(self, px):
        if self._size != px:
            self._size = px
            self.dirty = True

您遇到的问题是您的setter指的是在调用setter之前您未创建的属性 - self._size在您为其分配内容之前不存在。通常,我使用具有良好名称的属性(如size)并将数据存储在隐藏属性中(例如,_size)。在初始化程序中,我只是直接操作属性而不依赖于属性。

在您的情况下,设置属性会产生副作用,因此您可能会出现错误。请考虑如果将self.dirty = False作为初始化程序中的第一行,会发生什么。