【问题标题】:Why does trying to set "points" via Python properties cause infinite recursion?为什么尝试通过 Python 属性设置“点”会导致无限递归?
【发布时间】:2017-08-18 09:42:08
【问题描述】:

为什么尝试通过 Python 属性设置“点”会导致无限递归?

使用 Python 3

import Task

myTask = Task.Task("Test",-5)

myTask.points = -7

print(myTask)

class Task:

def __init__(self,name="",points=0,times_done=0):
    self.name = name
    self.points = points
    self.times_done = times_done

@property
def points(self):
    return self.points

@points.setter
def points(self, points):
    if (points < 0):
        self.points = 0
    else:
        self.points = points

def __str__(self):
    return "The task '" + self.name + "' is worth " + str(self.points) + " and has been completed " + str(self.times_done) + " times."

当它尝试使用值 -5 构造它(应该通过属性将其设置为 0)时,它会在 setter 函数/装饰 @points.setter. 中的 self.points = points 行上无限递归

谢谢!

【问题讨论】:

  • 我无法重现该错误。您是否在此处省略任何代码?
  • 只有那些根本不应该相关的东西。我会编辑它
  • @Julien,OP 应该使用 Python 3.x。如果您使用的是 python 2.x,通过从 object 继承,您可以重现:class Task(object)
  • 我使用的是 Python 3,是的

标签: python python-3.x recursion decorator getter-setter


【解决方案1】:

因为self.points = ...调用了setter;在 setter 内部,self.points = ... 被执行,它调用了 setter;递归重复直到堆栈溢出。

通过使用其他名称,可以防止递归:例如self._points

或者不使用self.points = ...,而是使用self.__dict__['points'] = ..(getter 相同):

@property
def points(self):
    return self.__dict__['points']

@points.setter
def points(self, points):
    if points < 0:
        self.__dict__['points'] = 0
    else:
        self.__dict__['points'] = points
    # self.__dict__['points'] = max(0, points)

【讨论】:

    【解决方案2】:

    那是因为在你的property setter 内部,它再次调用了自己:

    @points.setter
    def points(self, points):
        if (points < 0):
            self.points = 0 # call itself again here
        else:
            self.points = points # call itself again here
    

    使用property时需要另外一个字段来存储实际值,最好是"private" field

    class Task(object):
        def __init__(self,name="",points=0,times_done=0):
                self.name = name
                self.points = points
                self.times_done = times_done
    
        @property
        def points(self):
                return self._points
    
        @points.setter
        def points(self, points):
                if (points < 0):
                        self._points = 0
                else:
                        self._points = points
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-19
      • 1970-01-01
      • 2021-08-30
      相关资源
      最近更新 更多