【问题标题】:Python3 - using super() in __eq__ methods raises RuntimeError: super(): __class__ cell not foundPython3 - 在 __eq__ 方法中使用 super() 会引发 RuntimeError: super(): __class__ cell not found
【发布时间】:2017-10-02 09:34:29
【问题描述】:

我正在修补类的__eq__ 方法。我发现以下工作:

   def eq(obj, other):
       if isinstance(other, str):
          return obj.name.upper() == other.upper()
       else:
          return object.__eq__(obj, other)

这不起作用:

  def eq(obj, other):
     if isinstance(other, str):
         return obj.name.upper() == other.upper()
     else:
        return super().__eq__(other)

这有时有效,但有时会引发错误:

def eq(obj, other):
   if isinstance(other, str):
       return obj.name.upper() == other.upper()
   else:
       return super().__eq__(self, other)

错误:

<ipython-input-128-91287536205d> in eq(obj, other)
      3         return obj.name.upper() == other.upper()
      4     else:
----> 5         return super().__eq__(self, other)
      6 
      7 

RuntimeError: super(): __class__ cell not found

你能解释一下这里发生了什么吗?如何正确地将object 替换为super()

【问题讨论】:

  • 除了缩进之外,您的“不起作用”和“有时起作用”示例之间没有区别。只要没有到达else 分支,两者都只是“有时”工作。
  • 注意super(...).__eq__是一个绑定方法,所以第一个参数(通常命名为self)会自动从第二个参数传入super(cls, instance)。你只需要传入other:super(...).__eq__(other)
  • 我在类之外创建__new__ 时遇到了这个错误(动态地,出于测试目的,在实际代码中你真的不需要这种魔法),使用2-参数@ 987654335@ 像super(metaclass, cls).__new__(cls) 一样调用metaclass 几乎总是只是type 解决了这个问题

标签: python python-3.x super overloading monkeypatching


【解决方案1】:

你不能在类外定义的函数中使用不带参数的super()__class__ 单元格 super() 依赖仅提供给在 class 主体中定义的函数。来自super() documentation

零参数形式仅适用于类定义,因为编译器会填写必要的详细信息以正确检索正在定义的类,以及访问普通方法的当前实例。

使用 2 参数形式,明确命名类:

def eq(obj, other):
   if isinstance(other, str):
       return obj.name.upper() == other.upper()
   else:
       return super(ClassYouPutThisOn, obj).__eq__(other)

ClassYouPutThisOn.__eq__ = eq

这要求您在猴子补丁中显式命名类,从而减少重用的用处。

相反,您可以通过将eq 嵌套在另一个以__class__ 作为本地名称的函数中,手动提供所需的__class__ 单元格:

def patch_eq(cls):
    __class__ = cls  # provide closure cell for super()
    def eq(obj, other):
       if isinstance(other, str):
           return obj.name.upper() == other.upper()
       else:
           return super().__eq__(other)
    cls.__eq__ = eq

super() 通过从调用框架中获取第一个本地名称(即传递给函数调用的第一个参数,通常称为 self)来找到第二个参数(对实例的引用)。

另见Why is Python 3.x's super() magic?

使用嵌套函数方法的演示:

>>> class Foo:
...     name = 'bar'
...     def __eq__(self, other):
...         return False
...
>>> Foo() == 'Bar'
False
>>> Foo() == Foo()
False
>>> patch_eq(Foo)
>>> Foo() == 'Bar'
True
>>> Foo() == Foo()
False

【讨论】:

    猜你喜欢
    • 2015-09-09
    • 2018-03-12
    • 2013-11-15
    • 2010-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多