Python中Dict的查找
Dict的類型的查找使用的是lookdict函數(shù)
static PyDictKeyEntry * lookdict(PyDictObject *mp, PyObject *key,Py_hash_t hash, PyObject ***value_addr)函數(shù)的參數(shù)中,*value_addr是指向匹配slot中值的指針。 這個(gè)函數(shù)在正確的情況下一定會(huì)返回一個(gè)指向slot的指針,出錯(cuò)則會(huì)返回NULL。 如果成功找到了匹配的slot,則返回對(duì)應(yīng)的slot; 如果沒有匹配的slot,則返回查找鏈上第一個(gè)未被使用的slot。 該slot可以是unused狀態(tài),也可以是dummy狀態(tài)。
mask = DK_MASK(mp->ma_keys);ep0 = &mp->ma_keys->dk_entries[0];i = (size_t)hash & mask;計(jì)算了slot的初始位置,把hash值映射到slot table的下標(biāo)范圍內(nèi)。 初始位置=hash&mask,mask=dk_size-1
if (ep->me_key == NULL || ep->me_key == key) {*value_addr = &ep->me_value;return ep;}如果找到了匹配的key或unused slot,返回該結(jié)果即可。
if (ep->me_key == dummy)freeslot = ep;else {if (ep->me_hash == hash) {startkey = ep->me_key;Py_INCREF(startkey);cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);Py_DECREF(startkey);if (cmp < 0)return NULL;if (ep0 == mp->ma_keys->dk_entries && ep->me_key == startkey) {if (cmp > 0) {*value_addr = &ep->me_value;return ep;}}else {/* The dict was mutated, restart */goto top;}}freeslot = NULL;}進(jìn)一步的比較。 若該slot狀態(tài)為dummy,則用freeslot記錄該slot并繼續(xù)搜索; 如果該slot的hash值與待搜索key的hash相同,那么對(duì)兩個(gè)key進(jìn)行比較。 這里的PyObject_RichCompareBool是一個(gè)比較函數(shù),其第三個(gè)參數(shù)為比較的操作。 如果操作結(jié)果為true,返回1;為false,返回0;比較出錯(cuò),返回-1。 比較出錯(cuò)的情況下會(huì)返回NULL,比較成功(在這里為相等)返回該slot,比較不成功則繼續(xù)進(jìn)行搜索。 這一部分進(jìn)行了第一次的搜索;在dict容量不太滿時(shí),一般在這里就可以找到合適的結(jié)果。
i = (i << 2) + i + perturb + 1;ep = &ep0[i & mask];if (ep->me_key == NULL) {if (freeslot == NULL) {*value_addr = &ep->me_value;return ep;} else {*value_addr = &freeslot->me_value;return freeslot;}}找到了unused slot的情況。 如果freeslot是NULL,那么返回該slot即可;若freeslot不是NULL,那么返回freeslot。
if (ep->me_key == key) {*value_addr = &ep->me_value;return ep;}找到了匹配的key。此情況返回對(duì)應(yīng)slot即可。
if (ep->me_hash == hash && ep->me_key != dummy) {startkey = ep->me_key;Py_INCREF(startkey);cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);Py_DECREF(startkey);if (cmp < 0) {*value_addr = NULL;return NULL;}if (ep0 == mp->ma_keys->dk_entries && ep->me_key == startkey) {if (cmp > 0) {*value_addr = &ep->me_value;return ep;}}else {/* The dict was mutated, restart */goto top;}}該slot hash值與給定hash值相同時(shí)進(jìn)一步比較的情況。
else if (ep->me_key == dummy && freeslot == NULL)freeslot = ep;在dummy情況下設(shè)置freeslot。
?
在搜索過程中,原則是找到和key相等的對(duì)象即可。 那么什么是和key相等呢? 一種情況是它們的引用相等,自然的值也相等。 這類比較只需要直接比較對(duì)應(yīng)指針是否相等呢該即可。 而另一種情況是引用不相等,但值還相等。 如果沒有對(duì)這種情況的處理,那么對(duì)于非共享的對(duì)象來說搜索幾乎不會(huì)得到正確的結(jié)果。 搜索中的進(jìn)一步比較就是對(duì)這種情況的處理。 進(jìn)一步比較發(fā)生的前提是hash值相等,因?yàn)橹迪嗟缺厝挥衕ash相等, 但hash相等值卻可能不等,因此不能直接比較hash值,還需要更進(jìn)一步的比較值才可以。
轉(zhuǎn)載于:https://www.cnblogs.com/ruizhang3/p/6888006.html
總結(jié)
以上是生活随笔為你收集整理的Python中Dict的查找的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自己初学时的随笔记录
- 下一篇: python基础:迭代器、生成器(yie