2017-05-04 79 views
0

我是猴子修補類的__eq__方法。我發現了以下工作:Python3 - 在__eq__方法中使用super()會引發RuntimeError:super():__class__ cell not found

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 

你能解釋一下wh在這裏呢?如何正確地將object替換爲super()

+0

還有就是你的「不工作」和「有時作品的例子,除了壓痕彼此之間沒有什麼區別。只要沒有到達'else'分支,只有'有時'工作。 –

+0

請注意'super(...).__ eq__'是一個* bound方法*,所以第一個參數(通常命名爲'self')自動從第二個參數傳入'super(cls,instance)'。你只需要傳入'other':'super(...).__ eq __(other)'。 –

回答

2

在類的外部定義的函數中不能使用無參數的super()__class__單元格super()僅依賴於在class正文中定義的函數。從super() documentation

The zero argument form only works inside a class definition, as the compiler fills in the necessary details to correctly retrieve the class being defined, as well as accessing the current instance for ordinary methods.

使用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 

這需要你明確地命名猴子補丁類,使其重用用處不大。

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()發現的第二個參數(參考實例),通過取:

相反,可以通過在另一個函數與__class__嵌套eq作爲本地名稱手動提供所需__class__細胞來自呼叫幀的第一個本地名稱(即傳入函數調用的第一個參數,通常稱爲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 
+0

你的第一個版本會導致:'NameError:name'self'未定義'。這應該是'obj'。 – Oz123

+0

@ Oz123:兩個版本都遭受了這種痛苦。謝謝你指出,糾正! –

+0

最後,我得到這個錯誤:'TypeError:expected 1 arguments,goto 2 'got when'return super(ClassYouPutThisOn,obj).__ eq __(obj,other)' – Oz123