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

nin*_*key 5 python properties

我的“修复”是正确的/良好的实践方法吗?

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

如果我尝试使用self.sizein __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'
Run Code Online (Sandbox Code Playgroud)

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

  1. 忽略可能有额外检查的 setter
  2. 如果_text更改,代码可能会中断,但如果它使用该属性,则可能没问题。

有错误的代码:

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()
Run Code Online (Sandbox Code Playgroud)

我的修复:

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()
Run Code Online (Sandbox Code Playgroud)

Win*_*ert 5

   try:
        if self._size != px:            
            self._size = px
            self.dirty=True
    except:
        self._size = 14
        self.dirty = True
Run Code Online (Sandbox Code Playgroud)

except 是一个坏主意,因为您会捕获所有异常。您可能会不小心捕捉到其他一些异常并忽略它。那将是一个坏主意。Python 会出于各种原因抛出异常,而您最终会掩盖错误。出于同样的原因,您应该在 try 块中放置尽可能少的代码。

一种方法是:

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

if size_changed:
    self._size = size
    self.dirty = True
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)