辞書データ構造分析
/* The ma_values pointer is NULL for a combined table * or points to an array of PyObject* for a split table */ typedef struct { PyObject_HEAD Py_ssize_t ma_used; PyDictKeysObject *ma_keys; PyObject **ma_values; } PyDictObject; struct _dictkeysobject { Py_ssize_t dk_refcnt; Py_ssize_t dk_size; dict_lookup_func dk_lookup; Py_ssize_t dk_usable; PyDictKeyEntry dk_entries[1]; }; typedef struct { /* Cached hash code of me_key. */ Py_hash_t me_hash; PyObject *me_key; PyObject *me_value; /* This field is only meaningful for combined tables */ } PyDictKeyEntry;
上記の各フィールドの意味は次のとおりです:
- ob_refcnt、オブジェクトの参照カウント。
- ob_type、オブジェクトのデータ型。
- ma_used、現在のハッシュ テーブル内のデータの数。
- ma_keys は、キーと値のペアを保持する配列を指します。
- ma_values、これは値の配列を指しますが、_dictkeysobject の PyDictKeyEntry 配列内のオブジェクトも値を格納できるため、この値は必ずしも cpython の特定の実装で使用されるわけではありません。この値は、すべてのキーが文字列である場合にのみ使用できます。この記事では、PyDictKeyEntry の値は主に辞書の実装について説明するために使用されるため、この変数は無視してかまいません。
- dk_refcnt, これは参照カウントを表すためにも使用されます。これは辞書ビューに関連しています。原理は参照カウントと似ているため、ここでは無視します。
- dk_size、これはハッシュ テーブルのサイズを表し、2n である必要があります。この場合、モジュラー演算はビット単位の AND 演算に変えることができます。
- dk_lookup、これはハッシュ テーブルのルックアップ関数を表し、関数ポインターです。
- dk_usable は、現在の配列で使用できるキーと値のペアの数を示します。
- dk_entries、ハッシュ テーブル。キーと値のペアが実際に保存されます。 #ハッシュ テーブル全体のレイアウトは次のようになります。
#新しい辞書オブジェクトの作成
static PyObject *
dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *self;
PyDictObject *d;
assert(type != NULL && type->tp_alloc != NULL);
// 申请内存空间
self = type->tp_alloc(type, 0);
if (self == NULL)
return NULL;
d = (PyDictObject *)self;
/* The object has been implicitly tracked by tp_alloc */
if (type == &PyDict_Type)
_PyObject_GC_UNTRACK(d);
// 因为还没有增加数据 因此哈希表当中 ma_used = 0
d->ma_used = 0;
// 申请保存键值对的数组 PyDict_MINSIZE_COMBINED 是一个宏定义 值为 8 表示哈希表数组的最小长度
d->ma_keys = new_keys_object(PyDict_MINSIZE_COMBINED);
// 如果申请失败返回 NULL
if (d->ma_keys == NULL) {
Py_DECREF(self);
return NULL;
}
return self;
}
// new_keys_object 函数如下所示
static PyDictKeysObject *new_keys_object(Py_ssize_t size)
{
PyDictKeysObject *dk;
Py_ssize_t i;
PyDictKeyEntry *ep0;
assert(size >= PyDict_MINSIZE_SPLIT);
assert(IS_POWER_OF_2(size));
// 这里是申请内存的位置真正申请内存空间的大小为 PyDictKeysObject 的大小加上 size-1 个PyDictKeyEntry的大小
// 这里你可能会有一位为啥不是 size 个 PyDictKeyEntry 的大小 因为在结构体 PyDictKeysObject 当中已经申请了一个 PyDictKeyEntry 对象了
dk = PyMem_MALLOC(sizeof(PyDictKeysObject) +
sizeof(PyDictKeyEntry) * (size-1));
if (dk == NULL) {
PyErr_NoMemory();
return NULL;
}
// 下面主要是一些初始化的操作 dk_refcnt 设置成 1 因为目前只有一个字典对象使用 这个 PyDictKeysObject 对象
DK_DEBUG_INCREF dk->dk_refcnt = 1;
dk->dk_size = size; // 哈希表的大小
// 下面这行代码主要是表示哈希表当中目前还能存储多少个键值对 在 cpython 的实现当中允许有 2/3 的数组空间去存储数据 超过这个数则需要进行扩容
dk->dk_usable = USABLE_FRACTION(size); // #define USABLE_FRACTION(n) ((((n) << 1)+1)/3)
ep0 = &dk->dk_entries[0];
/* Hash value of slot 0 is used by popitem, so it must be initialized */
ep0->me_hash = 0;
// 将所有的键值对初始化成 NULL
for (i = 0; i < size; i++) {
ep0[i].me_key = NULL;
ep0[i].me_value = NULL;
}
dk->dk_lookup = lookdict_unicode_nodummy;
return dk;
}
ハッシュ テーブルの拡張メカニズムまず、ディクショナリ実装におけるハッシュ テーブルの拡張メカニズムを見てみましょう。ディクショナリに新しいデータを追加し続けると、ディクショナリは間もなく、その中のデータは配列の長さの 23 に達します。この時点で、それを拡張する必要があります。拡張後の配列のサイズは次のように計算されます: #define GROWTH_RATE(d) (((d)->ma_used*2)+((d)->ma_keys->dk_size>>1))
新しい配列のサイズは次のようになります。元のキーと値のペアの数に 2 を乗算し、元の配列の長さの半分を加えた値。 一般に、拡張には 3 つの主な手順があります。
新しい配列のサイズを計算します。 - 新しい配列を作成します。
- 元のハッシュ テーブルのデータを新しい配列に追加します (つまり、再ハッシュ プロセス)。
- 具体的な実装コードは次のとおりです。
static int insertion_resize(PyDictObject *mp) { return dictresize(mp, GROWTH_RATE(mp)); } static int dictresize(PyDictObject *mp, Py_ssize_t minused) { Py_ssize_t newsize; PyDictKeysObject *oldkeys; PyObject **oldvalues; Py_ssize_t i, oldsize; // 下面的代码的主要作用就是计算得到能够大于等于 minused 最小的 2 的整数次幂 /* Find the smallest table size > minused. */ for (newsize = PyDict_MINSIZE_COMBINED; newsize <= minused && newsize > 0; newsize <<= 1) ; if (newsize <= 0) { PyErr_NoMemory(); return -1; } oldkeys = mp->ma_keys; oldvalues = mp->ma_values; /* Allocate a new table. */ // 创建新的数组 mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { mp->ma_keys = oldkeys; return -1; } if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; oldsize = DK_SIZE(oldkeys); mp->ma_values = NULL; /* If empty then nothing to copy so just return */ if (oldsize == 1) { assert(oldkeys == Py_EMPTY_KEYS); DK_DECREF(oldkeys); return 0; } /* Main loop below assumes we can transfer refcount to new keys * and that value is stored in me_value. * Increment ref-counts and copy values here to compensate * This (resizing a split table) should be relatively rare */ if (oldvalues != NULL) { for (i = 0; i < oldsize; i++) { if (oldvalues[i] != NULL) { Py_INCREF(oldkeys->dk_entries[i].me_key); oldkeys->dk_entries[i].me_value = oldvalues[i]; } } } /* Main loop */ // 将原来数组当中的元素加入到新的数组当中 for (i = 0; i < oldsize; i++) { PyDictKeyEntry *ep = &oldkeys->dk_entries[i]; if (ep->me_value != NULL) { assert(ep->me_key != dummy); insertdict_clean(mp, ep->me_key, ep->me_hash, ep->me_value); } } // 更新一下当前哈希表当中能够插入多少数据 mp->ma_keys->dk_usable -= mp->ma_used; if (oldvalues != NULL) { /* NULL out me_value slot in oldkeys, in case it was shared */ for (i = 0; i < oldsize; i++) oldkeys->dk_entries[i].me_value = NULL; assert(oldvalues != empty_values); free_values(oldvalues); DK_DECREF(oldkeys); } else { assert(oldkeys->dk_lookup != lookdict_split); if (oldkeys->dk_lookup != lookdict_unicode_nodummy) { PyDictKeyEntry *ep0 = &oldkeys->dk_entries[0]; for (i = 0; i < oldsize; i++) { if (ep0[i].me_key == dummy) Py_DECREF(dummy); } } assert(oldkeys->dk_refcnt == 1); DK_DEBUG_DECREF PyMem_FREE(oldkeys); } return 0; }ディクショナリへのデータの挿入ディクショナリへのデータの挿入を続けると、おそらく、ハッシュの競合が発生した場合、ハッシュの競合を処理するディクショナリのメソッドは、ハッシュの競合を処理するためにコレクションで使用されるメソッドと基本的に同じです。どちらも開発アドレスのメソッドを使用します。ただし、このオープン アドレスの実装は、この方法は比較的複雑ですが、具体的な手順は以下の通りです。
以上がPython仮想マシンにおける辞書の実装原理は何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

forhandlinglaredataSetsinpython、usenumpyArrays forbetterperformance.1)numpyarraysarememory-effictientandfasterfornumericaloperations.2)nusinnnnedarytypeconversions.3)レバレッジベクトル化は、測定済みのマネージメーシェイメージーウェイズデイタイです

inpython、listsusedynamicmemoryallocation with allocation、whilenumpyArraysalocatefixedmemory.1)listsallocatemorememorythanneededededinitivative.2)numpyArrayasallocateexactmemoryforements、rededicablebutlessflexibilityを提供します。

inpython、youcanspecthedatatypeyfelemeremodelernspant.1)usenpynernrump.1)usenpynerp.dloatp.ploatm64、フォーマーpreciscontrolatatypes。

numpyisessentialfornumericalcomputinginpythonduetoitsspeed、memory efficiency、andcomprehensivematicalfunctions.1)それは、performsoperations.2)numpyArraysaremoremory-efficientthanpythonlists.3)Itofderangeofmathematicaloperty

contiguousMemoryAllocationisucial forArraysは、ForeffienceAndfastelementAccess.1)iteenablesConstantTimeAccess、O(1)、DuetodirectAddresscalculation.2)itemprovesefficiencyByAllowingMultiblementFechesperCacheLine.3)itimplifieMememm

slicingapythonlistisdoneusingtheyntaxlist [start:stop:step] .hore'showitworks:1)startisthe indexofthefirstelementtoinclude.2)spotisthe indexofthefirmenttoeexclude.3)staptistheincrementbetbetinelements

numpyallows forvariousoperationsonarrays:1)basicarithmeticlikeaddition、減算、乗算、および分割; 2)AdvancedperationssuchasmatrixMultiplication;

Arraysinpython、特にnumpyandpandas、aresentialfordataanalysis、offeringspeedandeficiency.1)numpyarraysenable numpyarraysenable handling forlaredatasents andcomplexoperationslikemoverages.2)Pandasextendsnumpy'scapabivitieswithdataframesfortruc


ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

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

MantisBT
Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

MinGW - Minimalist GNU for Windows
このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

mPDF
mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

AtomエディタMac版ダウンロード
最も人気のあるオープンソースエディター

ホットトピック









