Pythonのリスト長調整方法(コード付き)
この記事はPythonのリストの長さ調整方法(コード付き)についての内容であり、ある程度の参考値はありますので、困っている方は参考にしていただければ幸いです。
Python の list (リスト) は非常に柔軟な配列であり、長さを自由に調整できます。この利便性があるからこそ、必要に応じて配列を変更せずにはいられないのですが、insert や Pop などに比べて、append の使用が一般的です。
こんな風に使われることもあります:
>>> test = [] >>> test.append(1) >>> test.append({2}) >>> test.append([3]) >>> print test # 输出 [1, set([2]), [3]]
こんな風に使われることもあります:
test = [] for i in range(4): test.append(i) print test # 输出 [0, 1, 2, 3]
このように使えてとても嬉しいです。
しかし実際には、データ長が動的に変更される可能性があるシナリオ、つまりメモリ管理の問題に遭遇した場合には、すぐに対応する必要があります。
業務効率化と利便性が同時に実現できれば、それは素晴らしいことです。
しかし、神はあなたのために窓を開けるとき、必ずドアも閉めているはずです。
ペニーピンチ初期化
私たちは事前割り当ての知識に深く影響されており、初期化中にリストには一定の長さが割り当てられると感じています。毎回記憶を申請します。
実際、リストは非常に「少ない」です:
import sys test = [] test_1 = [1] print sys.getsizeof(test) print sys.getsizeof(test_1) - sys.getsizeof(test) # 输出 72 # 空列表内存大小,也是 list 对象的总大小 8 # 代表增加一个成员,list 增加的大小
私たちの推測では、リストが定義された後、データを埋めるために特定のサイズのプールが事前に割り当てられるのではないかと考えられます。 . 毎回メモリを申請することは避けてください。
しかし、上記の実験は、メンバー リストの長さが空のリストよりも 8 バイト大きいだけであることを示しています。そのような事前割り当てプールが実際に存在する場合、メンバーを追加するときに事前割り当てされたプールの数は、両方のメモリ サイズは変更されないはずです。
したがって、このリストにはそのような事前割り当てメモリ プールが存在すべきではないと推測できます。ここでは実際のハンマーが必要です。
PyObject * PyList_New(Py_ssize_t size) { PyListObject *op; size_t nbytes; if (size < 0) { PyErr_BadInternalCall(); return NULL; } /* Check for overflow without an actual overflow, * which can cause compiler to optimise out */ if ((size_t)size > PY_SIZE_MAX / sizeof(PyObject *)) return PyErr_NoMemory(); // list对象指针的缓存 if (numfree) { numfree--; op = free_list[numfree]; _Py_NewReference((PyObject *)op); } else { op = PyObject_GC_New(PyListObject, &PyList_Type); if (op == NULL) return NULL; } // list 成员的内存申请 nbytes = size * sizeof(PyObject *); if (size <= 0) op->ob_item = NULL; else { op->ob_item = (PyObject **) PyMem_MALLOC(nbytes); if (op->ob_item == NULL) { Py_DECREF(op); return PyErr_NoMemory(); } memset(op->ob_item, 0, nbytes); } Py_SIZE(op) = size; op->allocated = size; _PyObject_GC_TRACK(op); return (PyObject *) op; }
test = [1] を実行するとき、実際に行うことは次の 2 つだけです:
メンバーの数に基づいて、対応する長さの空のリストを構築します ;(上のコード)
これらのメンバーを 1 つずつ入れてください;
メンバーを詰めるステップで、何かのメカニズムがトリガーされて大きくなるのではないかと考える子供もいるかもしれません。
残念ですが、初期化メソッドは PyList_SET_ITEM なので、ここにはトリガー メカニズムはなく、配列メンバーの単純な割り当てだけです。
#define PyList_SET_ITEM(op, i, v) (((PyListObject *)(op))->ob_item[i] = (v))
したがって、リスト全体の初期化は次のようになります。本当に唯一のことは、事前に割り当てられたメモリ プールがないということです。オンデマンドで直接適用できます。すべてのニンジンは穴であり、これは本当に残酷です。
可変長の鍵
#初期化処理はこれは理解できますが、運用中にこのままだとちょっと無理があります。 想像してみてください。記事の冒頭の append の例で、要素が追加されるたびにメモリが適用されると、リストは生命を疑うほど批判される可能性があります。記憶を求めるとき、神にはまだ独自のルーチンがあるということです。 リストでは、挿入、ポップ、追加のいずれであっても、list_resize が使用されます。名前が示すように、この関数はリスト オブジェクトのメモリ使用量を調整するために使用されます。static int list_resize(PyListObject *self, Py_ssize_t newsize) { PyObject **items; size_t new_allocated; Py_ssize_t allocated = self->allocated; /* Bypass realloc() when a previous overallocation is large enough to accommodate the newsize. If the newsize falls lower than half the allocated size, then proceed with the realloc() to shrink the list. */ if (allocated >= newsize && newsize >= (allocated >> 1)) { assert(self->ob_item != NULL || newsize == 0); Py_SIZE(self) = newsize; return 0; } /* This over-allocates proportional to the list size, making room * for additional growth. The over-allocation is mild, but is * enough to give linear-time amortized behavior over a long * sequence of appends() in the presence of a poorly-performing * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ # 确定新扩展之后的占坑数 new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6); /* check for integer overflow */ if (new_allocated > PY_SIZE_MAX - newsize) { PyErr_NoMemory(); return -1; } else { new_allocated += newsize; } if (newsize == 0) new_allocated = 0; # 申请内存 items = self->ob_item; if (new_allocated <= (PY_SIZE_MAX / sizeof(PyObject *))) PyMem_RESIZE(items, PyObject *, new_allocated); else items = NULL; if (items == NULL) { PyErr_NoMemory(); return -1; } self->ob_item = items; Py_SIZE(self) = newsize; self->allocated = new_allocated; return 0; }
a = [1, 2, 3] a.append(1)
0 <= ob_size <= allocated len(list) == ob_size
#coding: utf8 import sys test = [] raw_size = sys.getsizeof(test) test.append(1) print "1 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size) test.append(1) print "2 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size) test.append(1) print "3 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size) test.append(1) print "4 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size) test.append(1) print "5 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size) test.append(1) print "6 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size)
# 输出结果 1 次 append 减去空列表的内存大小:32 2 次 append 减去空列表的内存大小:32 3 次 append 减去空列表的内存大小:32 4 次 append 减去空列表的内存大小:32 5 次 append 减去空列表的内存大小:64 6 次 append 减去空列表的内存大小:64
第 n 次 append | 列表原长度 | 新增成员数 | 原 allocated | newsize | new_allocated |
---|---|---|---|---|---|
1 | 0 | 1 | 0 | 0 + 1 = 1 | 3 + 1 = 4 |
2 | 1 | 1 | 4 | 1 + 1 = 2 | 无需改变 |
3 | 2 | 1 | 4 | 2 + 1 = 3 | 无需改变 |
4 | 3 | 1 | 4 | 3 + 1 = 4 | 无需改变 |
5 | 4 | 1 | 4 | 4 + 1 = 5 | 3 + 5 = 8 |
6 | 5 | 1 | 8 | 5 + 1 = 6 | 无需改变 |
通过上面的表格,应该比较清楚看到什么时候会触发改变 allocated,并且当触发时它们是如何计算的。为什么我们需要这样关注 allocated?理由很简单,因为这个值决定了整个 list 的动态内存的占用大小;
扩容是这样,缩容也是照猫画虎。反正都是算出新的 allocated, 然后由 PyMem_RESIZE 来处理。
总结
综上所述,在一些明确列表成员或者简单处理再塞入列表的情况下,我们不应该再用下面的方式:
test = [] for i in range(4): test.append(i) print test
而是应该用更加 pythonic 和 更加高效的列表推导式:test = [i for i in range(4)]。
以上がPythonのリスト長調整方法(コード付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









PHPとPythonにはそれぞれ独自の利点があり、プロジェクトの要件に従って選択します。 1.PHPは、特にWebサイトの迅速な開発とメンテナンスに適しています。 2。Pythonは、データサイエンス、機械学習、人工知能に適しており、簡潔な構文を備えており、初心者に適しています。

PythonはゲームとGUI開発に優れています。 1)ゲーム開発は、2Dゲームの作成に適した図面、オーディオ、その他の機能を提供し、Pygameを使用します。 2)GUI開発は、TKINTERまたはPYQTを選択できます。 TKINTERはシンプルで使いやすく、PYQTは豊富な機能を備えており、専門能力開発に適しています。

DebianシステムのReadDir関数は、ディレクトリコンテンツの読み取りに使用されるシステムコールであり、Cプログラミングでよく使用されます。この記事では、ReadDirを他のツールと統合して機能を強化する方法について説明します。方法1:C言語プログラムを最初にパイプラインと組み合わせて、cプログラムを作成してreaddir関数を呼び出して結果をinclude#include#include inctargc、char*argv []){dir*dir; structdireant*entry; if(argc!= 2){(argc!= 2){

限られた時間でPythonの学習効率を最大化するには、PythonのDateTime、時間、およびスケジュールモジュールを使用できます。 1. DateTimeモジュールは、学習時間を記録および計画するために使用されます。 2。時間モジュールは、勉強と休息の時間を設定するのに役立ちます。 3.スケジュールモジュールは、毎週の学習タスクを自動的に配置します。

この記事では、DebianシステムでNGINXSSL証明書を更新する方法について説明します。ステップ1:最初にCERTBOTをインストールして、システムがCERTBOTおよびPython3-Certbot-Nginxパッケージがインストールされていることを確認してください。インストールされていない場合は、次のコマンドを実行してください。sudoapt-getupdatesudoapt-getinstolcallcertbotthon3-certbot-nginxステップ2:certbotコマンドを取得して構成してlet'sencrypt証明書を取得し、let'sencryptコマンドを取得し、nginx:sudocertbot - nginxを構成します。

DebianシステムでHTTPSサーバーの構成には、必要なソフトウェアのインストール、SSL証明書の生成、SSL証明書を使用するWebサーバー(ApacheやNginxなど)の構成など、いくつかのステップが含まれます。 Apachewebサーバーを使用していると仮定して、基本的なガイドです。 1.最初に必要なソフトウェアをインストールし、システムが最新であることを確認し、ApacheとOpenSSL:sudoaptupdatesudoaptupgraysudoaptinstaをインストールしてください

DebianでGitLabプラグインを開発するには、特定の手順と知識が必要です。このプロセスを始めるのに役立つ基本的なガイドを以下に示します。最初にgitlabをインストールすると、debianシステムにgitlabをインストールする必要があります。 GitLabの公式インストールマニュアルを参照できます。 API統合を実行する前に、APIアクセストークンを取得すると、GitLabのAPIアクセストークンを最初に取得する必要があります。 gitlabダッシュボードを開き、ユーザー設定で「アクセストーケン」オプションを見つけ、新しいアクセストークンを生成します。生成されます

アパッチはインターネットの背後にあるヒーローです。それはWebサーバーであるだけでなく、膨大なトラフィックをサポートし、動的なコンテンツを提供する強力なプラットフォームでもあります。モジュラー設計を通じて非常に高い柔軟性を提供し、必要に応じてさまざまな機能を拡張できるようにします。ただし、モジュール性は、慎重な管理を必要とする構成とパフォーマンスの課題も提示します。 Apacheは、高度にカスタマイズ可能で複雑なニーズを満たす必要があるサーバーシナリオに適しています。
