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

Oz1*_*123 0 python overloading monkeypatching super python-3.x

我是猴子修补__eq__类的方法。我发现以下作品:

   def eq(obj, other):
       if isinstance(other, str):
          return obj.name.upper() == other.upper()
       else:
          return object.__eq__(obj, other)
Run Code Online (Sandbox Code Playgroud)

这不起作用:

  def eq(obj, other):
     if isinstance(other, str):
         return obj.name.upper() == other.upper()
     else:
        return super().__eq__(other)
Run Code Online (Sandbox Code Playgroud)

这有时可行,但有时会引发错误:

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

错误:

<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
Run Code Online (Sandbox Code Playgroud)

您能解释一下这里发生了什么吗?如何正确替换objectsuper()

Mar*_*ers 5

super()在类外部定义的函数中不能没有参数就不能使用。仅为主体中定义的功能提供依赖的__class__单元。从文档中super()classsuper()

零参数形式仅在类定义内起作用,因为编译器会填充必要的详细信息以正确检索所定义的类,以及为常规方法访问当前实例。

使用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
Run Code Online (Sandbox Code Playgroud)

这要求您在猴子补丁程序中显式命名该类,从而使其在重用时不太有用。

相反,您可以通过嵌套另一个函数作为本地名称来手动提供所需的__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
Run Code Online (Sandbox Code Playgroud)

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

另请参见为什么Python 3.x的super()有魔力?

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

>>> 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
Run Code Online (Sandbox Code Playgroud)