2016-03-29 11 views
3

Python listを拡張すると(例えば、mylist.extend()またはmylist += anotherlist)、リストのIDは変更されません。リストの後に連続したメモリが不十分な場合、CPythonはリストの拡張をどのように処理しますか?

私は(少なくともCPythonでは)リストがメモリ内で連続していることを理解しています(そしてIDはリストの先頭のアドレスになります)。リストの後のメモリがすでに断片化されていて、リスト拡張子を割り当てることができない場合(たとえその領域に不連続であっても十分な空き領域があっても)どうすればよいでしょうか?割り当てが失敗しますか?どのように緩和されていますか?

+1

https://github.com/python/cpython/blob/master/Objects/listobject.c –

+0

PyObjectを経由した間接参照は完璧な意味を持っています...私はスレッドを読んでいたときにスクロールして、 + =私は、リストの頭に直接*指されているリストIDの言葉を見たので、私はこれを聞いて終わりました。 – MartyMacGyver

答えて

2

CPythonでは、これはリストとタプルの割り当て方法の違いです。リストの場合、オブジェクトには、というポインタの内容が割り当てられています。適切なリストオブジェクトは小さく、移動する必要はありません。 からへのベクトルのアドレスは何度でも変更できます。

タプルオブジェクトの場合、ほとんどの場合、タプルオブジェクトのメモリは実際にはタプルオブジェクトに直接割り当てられます。しかし、タプルのサイズを変更することはできませんので、その場合はシナリオが発生しません。

+0

それでは、それは答えています。ポインタが実際の頭にあったのか、あなたが説明したように1段階の間接を持っているのか疑問に思いました。見通しでは、それはかなり明らかに見えるが、私は本当に応答を感謝します!(vs +の拡張についてのスレッドを読む際に、リストの頭に直接指されているリストのidという言葉が出てきたので、私はこれを求めたのです。) – MartyMacGyver

+0

良い質問でした! dictsやsetのような他の "潜在的に大きな可変オブジェクト"にも同じことが当てはまります:固定サイズのオブジェクトヘッダー( "id" - アドレス - 決して変更されません)に対する1つの割り当て、ヘッダーが_at_を指す可変サイズ部分。 –

+0

さて、それはCPythonのより多くのことでした...これは、このようにして、私が見つけたメモを誤って読んで、それが私を捨ててしまったことを完全に理解しています。私は元の質問を削除するだろうが、おそらくそれは初心者に使用されるだろう。私はPyConで恥のポケットプロテクターを着用しなければならないのだろうか? :-D – MartyMacGyver

1

これは実装固有のものですが、CPythonについて質問していると思います。

あなたが言うように、リストは連続したメモリですが、これはPyObjectsのCポインタ(*PyObject)です。オブジェクトそのものは、自分のクラスの整数やオブジェクトであれ、動的メモリのどこかに(おそらく)連続したメモリには割り当てられません。

リストが最初に割り当てられると、(概念的に)右側に「スラック」エントリを残して、必要以上のメモリが得られます。 list.append()は次のスラックエントリだけを使用します。もちろん、最終的に彼らはすべて満員です。

この時点で、メモリの再割り当てが実行されます。 C言語では、これはrealloc()への呼び出しですが、実際にはこの実装ではCランタイムヒープを使用しないことがあります。基本的には、動的メモリから大きなメモリ割り当てが得られ、リストのすべての要素が新しいリストにコピーされます。ただし、オブジェクト自体ではなく、Pythonオブジェクトへのポインタをコピーしています。

これを実行する際にオーバーヘッドがありますが、スラックエントリを使用するとオーバーヘッドが減ります。これにより、list.append()がリストの「左」にエントリを追加するより効率的であることがわかります。

新しいリストのメモリが不足しているため割り当てに失敗した場合、メモリ不足のエラーが発生します。しかし、メモリが不足していると、新しいPythonオブジェクトがこれを引き起こす可能性があります。

ヒープフラグメンテーションが問題になることがありますが、これを管理するにはPythonが最善です。これが、Pythonが独自のヒープ管理を行う理由の1つです。最近のWindowsの実装では、C RTLの代わりに低レベルの仮想メモリAPIが使用されるため、Pythonは独自のメモリ管理を実行できます。

+0

はい、これはCPythonに関係しており、私は今それを理解しています。 – MartyMacGyver

+0

良い質問だった。実装を知っていれば、 'extend()'よりも 'append()'を使うべき理由が分かります。 – cdarke

+0

私はそれがなぜ... 'extend() 'と' append() 'が実装で違うように見えるのか分かりません(上記の@ Padricのコメントで参照されているCPythonコード)。さらに、ドキュメントと、http://stackoverflow.com/questions/252703/python-append-vs-extendの長い議論では、コードを見ていると大きな違いは 'extend()'が反復するということです。 'append()'への複数の手動呼び出し。これとコードの最適化の間に、あるリストから別のリストに要素を追加するときには、extend()が一般的に速いようです。思考? – MartyMacGyver

関連する問題