1. ホーム
  2. python

[解決済み] a]がオーバーロケートされる原因は何ですか?

2022-05-03 08:04:12

質問

どうやら list(a) はオーバーロケートしない。 [x for x in a] は、ある時点でオーバーロックされ [*a] オーバーオールロケート ずっと ?

以下は、0から12までのサイズnと、3つの方法での結果のバイト数です。

0 56 56 56
1 64 88 88
2 72 88 96
3 80 88 104
4 88 88 112
5 96 120 120
6 104 120 128
7 112 120 136
8 120 120 152
9 128 184 184
10 136 184 192
11 144 184 200
12 152 184 208

このように計算されます。 repl.itで再現可能 Python 3を使用しています。 8 :

from sys import getsizeof

for n in range(13):
    a = [None] * n
    print(n, getsizeof(list(a)),
             getsizeof([x for x in a]),
             getsizeof([*a]))

では これはどのように機能するのでしょうか? どのように [*a] オーバーロケート?実際、与えられた入力から結果リストを作成するのに、どのようなメカニズムを使っているのでしょうか?に対するイテレータを使用しているのでしょうか? a のようなものを使用し list.append ? ソースコードはどこですか?

( データとコードで構成されるラボ 画像を生成したもの)

ズームインして小さくしたn。

ズームアウトして拡大したn。

解決方法は?

[*a] は、内部的にはC言語と同等の :

  1. 新しい、空の list
  2. 電話 newlist.extend(a)
  3. リターン list .

ということで、テストを展開すると。

from sys import getsizeof

for n in range(13):
    a = [None] * n
    l = []
    l.extend(a)
    print(n, getsizeof(list(a)),
             getsizeof([x for x in a]),
             getsizeof([*a]),
             getsizeof(l))

オンラインでお試しください

の結果が表示されます。 getsizeof([*a])l = []; l.extend(a); getsizeof(l) は同じです。

これは通常正しいことです。 extend 一般化されたアンパッキングでも同様に、複数のものが次々と追加されることが想定されています。 [*a] は通常の場合ではありません。Pythonは、複数のアイテムや反復記号が list ( [*a, b, c, *d] )であるため、オーバーロケーションは一般的なケースで作業を軽減することができます。

これに対して list は、1つの大きさの反復記号から構成されます ( list() は、使用中に大きくなったり小さくなったりすることはなく、そうでないことが証明されるまでは、オーバーロケートは時期尚早です。 Python は最近、サイズがわかっている入力に対してもコンストラクタをオーバーオールするバグを修正しました。 .

については list 内包は、事実上繰り返される append のように、一度に1つの要素を追加する場合、通常のオーバーオールロケーションの成長パターンの最終結果を見ることができます。

はっきり言って、これはどれも言語保証ではありません。CPythonがどのように実装しているかを示しているに過ぎません。Python の言語仕様では、一般的に list (償却された O(1) appendpop を末尾から削除)。コメントで指摘されているように、具体的な実装は3.9で再び変更されます。 [*a] のようなケースに影響を与える可能性があります。 tuple 個々のアイテムの extend と共に tuple が複数回適用されるようになりました。 LIST_APPEND そのため、オーバーロケーションが発生するタイミングや、計算に使用する数値が変わる可能性があります。