【问题标题】:Why aren't these magic methods recursive?为什么这些魔术方法不是递归的?
【发布时间】:2016-01-15 14:25:37
【问题描述】:

这是一个 Python 类,它实现了一些 magic methods:

class A():
    def __init__(self, value):
        self.value = value

    def inc(self):
        self.value += 1
        return self.value

    def dec(self):
        self.value -= 1
        return self.value

    def __eq__(self, other):
        return self.value == other

    def __gt__(self, other):
        return self.value > other

    def __lt__(self, other):
        return self.value < other

    def __setattr__(self, name, value):
        try:
            self.value
        except:
            pass
        else:
            print(name, "changed its value from", self.value, "to", value)
        finally:
            super().__setattr__(name, value)

它实现了在某些对象上定义的(尽管是多余的)方法,并允许比较和(在__setattr__ 情况下)赋值挂钩:

>>> a.inc()
value changed its value from 0 to 1
1

假设我们重新定义__setattr__ 使其更简单:

def __setattr__(self, name, value):
    self.__setattr__(name, value)

现在尝试分配给self.value 会让你一记耳光:

  File "<pyshell#50>", line 17, in __setattr__
    self.__setattr__(name, value)
  File "<pyshell#50>", line 17, in __setattr__
    self.__setattr__(name, value)
  File "<pyshell#50>", line 17, in __setattr__
    self.__setattr__(name, value)
  File "<pyshell#50>", line 17, in __setattr__
    self.__setattr__(name, value)
  File "<pyshell#50>", line 17, in __setattr__
    self.__setattr__(name, value)
RecursionError: maximum recursion depth exceeded

嗯,这是意料之中的。函数__setattr__是递归的;这就是为什么我们需要使用super()。

我的问题是,为什么这种递归不适用于其他魔术方法?也就是说,当我调用obj.__gt__(otherval) 时,与说obj &gt; otherval 相同,即调用obj.__gt__(otherval),即调用...

它不会导致方法中使用的&gt; 调用它自己的方法。为什么?

【问题讨论】:

  • 您希望self.value 在__setattr__ 中做什么?你永远不会在任何地方删除该属性,所以try..except..else 总是转到else。
  • 这不是重点。他只是在证明 __setattr__() 是递归的,但 __gt__() 不是。
  • @MartijnPieters 在初始化A 的实例时,您将得到name self.value 未定义,因为该值在没有先存在的情况下无法设置。删除 try 块,尝试打印分配的值,你就会明白我的意思了。
  • __setattr__ 正在陷入死循环,是的,因为您明确调用它。
  • @MartijnPieters 是的,a.inc() 或类似的。

标签: python python-3.x recursion operator-overloading


【解决方案1】:

您没有在 self 上调用 &gt;。您在 self.value 上调用它,它是一个整数值(例如完全不同的类型)。

如果你使用过:

def __gt__(self, other):
    return self > other

你也会陷入无限循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-18
    • 2020-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多