3

最近、Python で何かが頭をよぎりました: x = y(z)is equal to x = y.__call__(z). ただし、テストはその仮定を無効にするように見え、Python のインタープリターがクラッシュする原因にもなります。

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)

2 番目を実行すると、 ret(1, 2, 3)Python がクラッシュし、コマンド プロンプト ( image ) に戻ります。

  1. ret = ret.__call__ラインが実行されるとき、バックグラウンドで何が起こっていますか?
  2. Python が最後の行で動作を停止するのはなぜですか? また、バグとして報告する必要がありますか?

役に立たないリファレンス: Python 関数とその__call__属性

4

1 に答える 1

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 個のメモリ ラッパーを保持します。

于 2012-12-04T22:16:26.040 に答える