nvli123 发表于 2023-6-19 17:16:42

属性访问魔法方法中死循环的理解

>>> class Rectangle:
...   def __init__(self,width=0,height=0):
...         self.width=width
...         self.height=height
...   def __setattr__(self,name,value):
...         if name=='square':
...             self.width=value
...             self.height=value
...         else:
...             self.name=value
...   def getarea(self):
...         return self.width*self.height

else下一句self.name=value,这里会在实例化对象时触发死循环,我大概能理解
但是if name=='square':下面的self.width=value,self.height=value,应该也会触发死循环吧,当square赋值时,触发__setattr__()魔法方法,执行self.width=value,self.height=value,这里执行会再次触发__setattr__()魔法方法。
可实际上没报错,这是为什么

isdkz 发表于 2023-6-19 17:31:11

你的理解是对的,这段代码中存在一个问题,它的确会导致无限递归,这是因为__setattr__方法会在尝试对属性进行赋值操作时被调用,如果在__setattr__方法内部再次对属性进行赋值,就会再次调用__setattr__ ,从而形成无限递归。

然而,这个代码块的行为可能取决于你使用的 Python 的具体版本或实现。在某些版本或实现中,这可能不会引发错误,因为 Python 有一些内部机制可能会防止这种无限递归。

然而,最佳的做法是避免这种情况的发生。如果你希望在设置属性值时执行某些操作,你可以使用 property 装饰器来实现,而不是覆盖__setattr__ 。例如:

class Rectangle:
    def __init__(self, width=0, height=0):
      self._width = width
      self._height = height

    @property
    def width(self):
      return self._width

    @width.setter
    def width(self, value):
      self._width = value

    @property
    def height(self):
      return self._height

    @height.setter
    def height(self, value):
      self._height = value

    @property
    def square(self):
      return self._width * self._height

    @square.setter
    def square(self, value):
      self._width = value
      self._height = value

    def getarea(self):
      return self._width * self._height


在这个版本中,我使用了前导下划线的属性_width和_height来存储宽度和高度的值。当你尝试获取width 、 height或square的值时,会返回这些内部属性的值;当你尝试设置这些属性的值时,会更新内部属性的值,而不会引发无限递归。

nvli123 发表于 2023-6-19 17:43:08

isdkz 发表于 2023-6-19 17:31
你的理解是对的,这段代码中存在一个问题,它的确会导致无限递归,这是因为__setattr__方法会在尝试对 ...

回答的好详细呀,还给出了解决办法
非常感谢

歌者文明清理员 发表于 2023-6-19 22:38:06

isdkz 发表于 2023-6-19 17:31
你的理解是对的,这段代码中存在一个问题,它的确会导致无限递归,这是因为__setattr__方法会在尝试对 ...

wc
页: [1]
查看完整版本: 属性访问魔法方法中死循环的理解