2012-12-04 70 views
3

最近在Python中出現了一些東西:x = y(z)相當於x = y.__call__(z)。然而,一個測試似乎使這個假設無效,並導致Python的解釋器崩潰。執行`func = func .__ call__`時會發生什麼?

Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit (Intel)] on win32 
Type "help", "copyright", "credits" or "license" for more information. 
>>> def ret(*args): 
...  return args 
... 
>>> ret(1, 2, 3) 
(1, 2, 3) 
>>> for _ in range(1000000): 
...  ret = ret.__call__ 
... 
>>> ret(1, 2, 3) 

運行第二ret(1, 2, 3)導致Python的崩潰並返回到命令提示符(image)。

  1. ret = ret.__call__執行後會發生什麼情況?
  2. 爲什麼Python在最後一行停止工作,並且應該將其報告爲錯誤?

無用參考:Python functions and their __call__ attribute

+1

我不能在2.7或3.2.3中重現它。 – senderle

+1

也不對3.3.0。您是否錯誤地輸入了 –

+0

?可能是你的意思是'ret = ret .__ call __(_)' – akaRem

回答

1

您正在創建方法包裝的深度嵌套的結構。每種方法的包裝仍然有self,其中self是父類的方法包裝基準的基準,回到原來的功能,所有的方式:

>>> ret, ret.__call__.__self__ 
(<function ret at 0x10f17a050>, <function ret at 0x10f17a050>) 
>>> ret.__call__, ret.__call__.__call__.__self__ 
(<method-wrapper '__call__' of function object at 0x10f17a050>, <method-wrapper '__call__' of function object at 0x10f17a050>) 

注意該方法如何包裝__self__屬性點的內存地址父對象。

如果您創建了足夠的這些包裝,則可能會導致內存不足。

Python爲所有綁定到實例的函數創建了這樣的包裝器。它是一個方法的自定義類一樣:

>>> class Foo: 
...  def bar(self): return 
... 
>>> Foo().bar 
<bound method Foo.bar of <__main__.Foo object at 0x10f1798d0>> 
>>> Foo().bar, Foo().bar.__self__ 
(<bound method Foo.bar of <__main__.Foo object at 0x10f179710>>, <__main__.Foo object at 0x10f179850>) 

方法是由函數創建的需要,通過訪問屬性訪問方法時。因爲他們持有對self的引用,所以只要您持有對引用的引用,它們就會保留在內存中。因此,您的參考鏈持續存在100000個內存包裝。

+0

謝謝!我添加了一個圖像來質疑計算機告訴我的內容。我感到困惑的是爲什麼Python不會生成一個'RuntimeError'而只是退出。 –

相關問題