Python3 - 在__eq__方法中使用super()引发RuntimeError:super():找不到__class__单元格

时间:2017-05-04 09:25:00

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

我正在修补类的__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()

1 个答案:

答案 0 :(得分:4)

在类外部定义的函数中,不能使用不带参数的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

这要求您在Monkey补丁中明确命名该类,使其不再有用。

相反,您可以将__class__嵌套在另一个以eq作为本地名称的函数中,手动提供所需的__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)来查找第二个参数(对实例的引用)。 / p>

另见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