【问题标题】:using python @property in __init__ , gives attribute error在 __init__ 中使用 python @property,给出属性错误
【发布时间】:2011-12-16 00:51:52
【问题描述】:

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

我有一个 Text() 类,它缓存要渲染的表面,除非字体/大小发生变化。 (我从 sn-p 中留下了字体属性)

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

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'

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

  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()

我的修复:

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()

【问题讨论】:

  • 为什么要在__init__ 期间使用该属性才能开始?根据定义,当您创建一个新实例时,它的属性无论如何都是新的/脏的!只需在 __init__ 期间直接设置 self._size,IMO。

标签: python properties


【解决方案1】:
   try:
        if self._size != px:            
            self._size = px
            self.dirty=True
    except:
        self._size = 14
        self.dirty = True

except 是个坏主意,因为您会捕获所有异常。您可能会不小心捕捉到其他一些异常并忽略它。那将是一个坏主意。 Python 会出于各种原因抛出异常,而您最终会掩盖错误。出于同样的原因,您应该在 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

【讨论】:

    【解决方案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 作为初始化程序的第一行会发生什么。

    【讨论】:

    • +1 关于行顺序的微妙重要性的精彩观点
    猜你喜欢
    • 2011-08-06
    • 2018-11-05
    • 1970-01-01
    • 2013-03-27
    • 2021-07-18
    • 2015-04-30
    • 2019-05-31
    • 1970-01-01
    • 2017-06-29
    相关资源
    最近更新 更多