1. 程式人生 > 程式設計 >Python字典新增,刪除,查詢等相關操作方法詳解

Python字典新增,刪除,查詢等相關操作方法詳解

一、建立增加修改

1、實現程式碼

#建立
stu_info = { "xiedi":28,"liuhailin":27,"daiqiao":30,"hanwenhai":25,"chenqun":38}
print(stu_info)
#增加
stu_info["luoahong"]=32
print(stu_info)
#修改
stu_info["xiedi"]=29
print(stu_info)

輸出結果

{'xiedi': 28,'liuhailin': 27,'daiqiao': 30,'hanwenhai': 25,'chenqun': 38}
{'xiedi': 28,'chenqun': 38,'luoahong': 32}
{'xiedi': 29,'luoahong': 32}

二、刪除(del)

1、實現程式碼

del stu_info["chenqun"]
print(stu_info)

2、輸出結果

{'xiedi': 29,'luoahong': 32}

 1、Dict_DelItem 

int
PyDict_DelItem(PyObject *op,PyObject *key)
{
  Py_hash_t hash;
  assert(key);
  if (!PyUnicode_CheckExact(key) ||
    (hash = ((PyASCIIObject *) key)->hash) == -1) {
    hash = PyObject_Hash(key);
    if (hash == -1)
      return -1;
  }

  return _PyDict_DelItem_KnownHash(op,key,hash);
}

2、Dict_DelItem_KnownHash

int
_PyDict_DelItem_KnownHash(PyObject *op,PyObject *key,Py_hash_t hash)
{
  Py_ssize_t ix;
  PyDictObject *mp;
  PyObject *old_value;

  if (!PyDict_Check(op)) {
    PyErr_BadInternalCall();
    return -1;
  }
  assert(key);
  assert(hash != -1);
  mp = (PyDictObject *)op;
  ix = (mp->ma_keys->dk_lookup)(mp,hash,&old_value);
  if (ix == DKIX_ERROR)
    return -1;
  if (ix == DKIX_EMPTY || old_value == NULL) {
    _PyErr_SetKeyError(key);
    return -1;
  }

  // Split table doesn't allow deletion. Combine it.
  if (_PyDict_HasSplitTable(mp)) {
    if (dictresize(mp,DK_SIZE(mp->ma_keys))) {
      return -1;
    }
    ix = (mp->ma_keys->dk_lookup)(mp,&old_value);
    assert(ix >= 0);
  }

  return delitem_common(mp,ix,old_value);
}

/* This function promises that the predicate -> deletion sequence is atomic
 * (i.e. protected by the GIL),assuming the predicate itself doesn't
 * release the GIL.
 */

3、PyDict_DelItemIf

int
_PyDict_DelItemIf(PyObject *op,int (*predicate)(PyObject *value))
{
  Py_ssize_t hashpos,ix;
  PyDictObject *mp;
  Py_hash_t hash;
  PyObject *old_value;
  int res;

  if (!PyDict_Check(op)) {
    PyErr_BadInternalCall();
    return -1;
  }
  assert(key);
  hash = PyObject_Hash(key);
  if (hash == -1)
    return -1;
  mp = (PyDictObject *)op;
  ix = (mp->ma_keys->dk_lookup)(mp,&old_value);
    assert(ix >= 0);
  }

  res = predicate(old_value);
  if (res == -1)
    return -1;

  hashpos = lookdict_index(mp->ma_keys,ix);
  assert(hashpos >= 0);

  if (res > 0)
    return delitem_common(mp,hashpos,old_value);
  else
    return 0;
}

二、刪除pop(k)

實現

stu_info = { "xiedi":28,"chenqun":38}
print(stu_info)
stu_info.pop("liuhailin")
print(stu_info)

輸出結果:

{'xiedi': 28,'chenqun': 38}

1、_PyDict_Pop

PyObject *
_PyDict_Pop(PyObject *dict,PyObject *deflt)
{
  Py_hash_t hash;

  if (((PyDictObject *)dict)->ma_used == 0) {
    if (deflt) {
      Py_INCREF(deflt);
      return deflt;
    }
    _PyErr_SetKeyError(key);
    return NULL;
  }
  if (!PyUnicode_CheckExact(key) ||
    (hash = ((PyASCIIObject *) key)->hash) == -1) {
    hash = PyObject_Hash(key);
    if (hash == -1)
      return NULL;
  }
  return _PyDict_Pop_KnownHash(dict,deflt);
}

2、_PyDict_Pop_KnownHash

/* Internal version of dict.pop(). */
PyObject *
_PyDict_Pop_KnownHash(PyObject *dict,Py_hash_t hash,PyObject *deflt)
{
  Py_ssize_t ix,hashpos;
  PyObject *old_value,*old_key;
  PyDictKeyEntry *ep;
  PyDictObject *mp;

  assert(PyDict_Check(dict));
  mp = (PyDictObject *)dict;

  if (mp->ma_used == 0) {
    if (deflt) {
      Py_INCREF(deflt);
      return deflt;
    }
    _PyErr_SetKeyError(key);
    return NULL;
  }
  ix = (mp->ma_keys->dk_lookup)(mp,&old_value);
  if (ix == DKIX_ERROR)
    return NULL;
  if (ix == DKIX_EMPTY || old_value == NULL) {
    if (deflt) {
      Py_INCREF(deflt);
      return deflt;
    }
    _PyErr_SetKeyError(key);
    return NULL;
  }

  // Split table doesn't allow deletion. Combine it.
  if (_PyDict_HasSplitTable(mp)) {
    if (dictresize(mp,DK_SIZE(mp->ma_keys))) {
      return NULL;
    }
    ix = (mp->ma_keys->dk_lookup)(mp,&old_value);
    assert(ix >= 0);
  }

  hashpos = lookdict_index(mp->ma_keys,ix);
  assert(hashpos >= 0);
  assert(old_value != NULL);
  mp->ma_used--;
  mp->ma_version_tag = DICT_NEXT_VERSION();
  dictkeys_set_index(mp->ma_keys,DKIX_DUMMY);
  ep = &DK_ENTRIES(mp->ma_keys)[ix];
  ENSURE_ALLOWS_DELETIONS(mp);
  old_key = ep->me_key;
  ep->me_key = NULL;
  ep->me_value = NULL;
  Py_DECREF(old_key);

  ASSERT_CONSISTENT(mp);
  return old_value;
}

三、隨機刪除一個元素popitem()

stu_info = { "xiedi":28,"chenqun":38}
print(stu_info)
stu_info.popitem()
print(stu_info)

輸出結果:

{'xiedi': 28,'hanwenhai': 25}

1、dict_popitem_impl

/*[clinic input]
dict.popitem

Remove and return a (key,value) pair as a 2-tuple.

Pairs are returned in LIFO (last-in,first-out) order.
Raises KeyError if the dict is empty.
[clinic start generated code]*/

static PyObject *
dict_popitem_impl(PyDictObject *self)
/*[clinic end generated code: output=e65fcb04420d230d input=1c38a49f21f64941]*/
{
  Py_ssize_t i,j;
  PyDictKeyEntry *ep0,*ep;
  PyObject *res;

  /* Allocate the result tuple before checking the size. Believe it
   * or not,this allocation could trigger a garbage collection which
   * could empty the dict,so if we checked the size first and that
   * happened,the result would be an infinite loop (searching for an
   * entry that no longer exists). Note that the usual popitem()
   * idiom is "while d: k,v = d.popitem()". so needing to throw the
   * tuple away if the dict *is* empty isn't a significant
   * inefficiency -- possible,but unlikely in practice.
   */
  res = PyTuple_New(2);
  if (res == NULL)
    return NULL;
  if (self->ma_used == 0) {
    Py_DECREF(res);
    PyErr_SetString(PyExc_KeyError,"popitem(): dictionary is empty");
    return NULL;
  }
  /* Convert split table to combined table */
  if (self->ma_keys->dk_lookup == lookdict_split) {
    if (dictresize(self,DK_SIZE(self->ma_keys))) {
      Py_DECREF(res);
      return NULL;
    }
  }
  ENSURE_ALLOWS_DELETIONS(self);

  /* Pop last item */
  ep0 = DK_ENTRIES(self->ma_keys);
  i = self->ma_keys->dk_nentries - 1;
  while (i >= 0 && ep0[i].me_value == NULL) {
    i--;
  }
  assert(i >= 0);

  ep = &ep0[i];
  j = lookdict_index(self->ma_keys,ep->me_hash,i);
  assert(j >= 0);
  assert(dictkeys_get_index(self->ma_keys,j) == i);
  dictkeys_set_index(self->ma_keys,j,DKIX_DUMMY);

  PyTuple_SET_ITEM(res,ep->me_key);
  PyTuple_SET_ITEM(res,1,ep->me_value);
  ep->me_key = NULL;
  ep->me_value = NULL;
  /* We can't dk_usable++ since there is DKIX_DUMMY in indices */
  self->ma_keys->dk_nentries = i;
  self->ma_used--;
  self->ma_version_tag = DICT_NEXT_VERSION();
  ASSERT_CONSISTENT(self);
  return res;
}

四、查詢(key值在字典中存在) 

1、dict_keys

static PyObject *
dict_keys(PyDictObject *mp)
{
  PyObject *v;
  Py_ssize_t i,j;
  PyDictKeyEntry *ep;
  Py_ssize_t n,offset;
  PyObject **value_ptr;

 again:
  n = mp->ma_used;
  v = PyList_New(n);
  if (v == NULL)
    return NULL;
  if (n != mp->ma_used) {
    /* Durnit. The allocations caused the dict to resize.
     * Just start over,this shouldn't normally happen.
     */
    Py_DECREF(v);
    goto again;
  }
  ep = DK_ENTRIES(mp->ma_keys);
  if (mp->ma_values) {
    value_ptr = mp->ma_values;
    offset = sizeof(PyObject *);
  }
  else {
    value_ptr = &ep[0].me_value;
    offset = sizeof(PyDictKeyEntry);
  }
  for (i = 0,j = 0; j < n; i++) {
    if (*value_ptr != NULL) {
      PyObject *key = ep[i].me_key;
      Py_INCREF(key);
      PyList_SET_ITEM(v,key);
      j++;
    }
    value_ptr = (PyObject **)(((char *)value_ptr) + offset);
  }
  assert(j == n);
  return v;
}

2、PyDict_Keys

PyObject *
PyDict_Keys(PyObject *mp)
{
  if (mp == NULL || !PyDict_Check(mp)) {
    PyErr_BadInternalCall();
    return NULL;
  }
  return dict_keys((PyDictObject *)mp);
}

PyObject *
PyDict_Values(PyObject *mp)
{
  if (mp == NULL || !PyDict_Check(mp)) {
    PyErr_BadInternalCall();
    return NULL;
  }
  return dict_values((PyDictObject *)mp);
}

五、get(k)

1、dict_get_impl

static PyObject *
dict_get_impl(PyDictObject *self,PyObject *default_value)
/*[clinic end generated code: output=bba707729dee05bf input=279ddb5790b6b107]*/
{
  PyObject *val = NULL;
  Py_hash_t hash;
  Py_ssize_t ix;

  if (!PyUnicode_CheckExact(key) ||
    (hash = ((PyASCIIObject *) key)->hash) == -1) {
    hash = PyObject_Hash(key);
    if (hash == -1)
      return NULL;
  }
  ix = (self->ma_keys->dk_lookup) (self,&val);
  if (ix == DKIX_ERROR)
    return NULL;
  if (ix == DKIX_EMPTY || val == NULL) {
    val = default_value;
  }
  Py_INCREF(val);
  return val;
}

2、_PyDict_GetItem_KnownHash

/* Same as PyDict_GetItemWithError() but with hash supplied by caller.
  This returns NULL *with* an exception set if an exception occurred.
  It returns NULL *without* an exception set if the key wasn't present.
*/
PyObject *
_PyDict_GetItem_KnownHash(PyObject *op,Py_hash_t hash)
{
  Py_ssize_t ix;
  PyDictObject *mp = (PyDictObject *)op;
  PyObject *value;

  if (!PyDict_Check(op)) {
    PyErr_BadInternalCall();
    return NULL;
  }

  ix = (mp->ma_keys->dk_lookup)(mp,&value);
  if (ix < 0) {
    return NULL;
  }
  return value;
}

3、_PyDict_GetItemId

PyObject *
_PyDict_GetItemId(PyObject *dp,struct _Py_Identifier *key)
{
  PyObject *kv;
  kv = _PyUnicode_FromId(key); /* borrowed */
  if (kv == NULL) {
    PyErr_Clear();
    return NULL;
  }
  return PyDict_GetItem(dp,kv);
}

/* For backward compatibility with old dictionary interface */

4、PyDict_GetItemString

PyObject *
PyDict_GetItemString(PyObject *v,const char *key)
{
  PyObject *kv,*rv;
  kv = PyUnicode_FromString(key);
  if (kv == NULL) {
    PyErr_Clear();
    return NULL;
  }
  rv = PyDict_GetItem(v,kv);
  Py_DECREF(kv);
  return rv;
}

int
_PyDict_SetItemId(PyObject *v,struct _Py_Identifier *key,PyObject *item)
{
  PyObject *kv;
  kv = _PyUnicode_FromId(key); /* borrowed */
  if (kv == NULL)
    return -1;
  return PyDict_SetItem(v,kv,item);
}

int
PyDict_SetItemString(PyObject *v,const char *key,PyObject *item)
{
  PyObject *kv;
  int err;
  kv = PyUnicode_FromString(key);
  if (kv == NULL)
    return -1;
  PyUnicode_InternInPlace(&kv); /* XXX Should we really? */
  err = PyDict_SetItem(v,item);
  Py_DECREF(kv);
  return err;
}

六、setdefault(k,v)

setdefault()表示去取字典中的key,如果取不到,則設定新值,相反如果取到,則返回原有預設值

1、dict_setdefault_impl 

/*[clinic input]
dict.setdefault
  key: object
  default: object = None
  /
Insert key with a value of default if key is not in the dictionary.
Return the value for key if key is in the dictionary,else default.
[clinic start generated code]*/

static PyObject *
dict_setdefault_impl(PyDictObject *self,PyObject *default_value)
/*[clinic end generated code: output=f8c1101ebf69e220 input=0f063756e815fd9d]*/
{
  PyObject *val;

  val = PyDict_SetDefault((PyObject *)self,default_value);
  Py_XINCREF(val);
  return val;
}

static PyObject *
dict_clear(PyDictObject *mp,PyObject *Py_UNUSED(ignored))
{
  PyDict_Clear((PyObject *)mp);
  Py_RETURN_NONE;
}

/*[clinic input]
dict.pop
  key: object
  default: object = NULL
  /

2、PyDict_SetDefault

PyObject *
PyDict_SetDefault(PyObject *d,PyObject *defaultobj)
{
  PyDictObject *mp = (PyDictObject *)d;
  PyObject *value;
  Py_hash_t hash;

  if (!PyDict_Check(d)) {
    PyErr_BadInternalCall();
    return NULL;
  }

  if (!PyUnicode_CheckExact(key) ||
    (hash = ((PyASCIIObject *) key)->hash) == -1) {
    hash = PyObject_Hash(key);
    if (hash == -1)
      return NULL;
  }
  if (mp->ma_keys == Py_EMPTY_KEYS) {
    if (insert_to_emptydict(mp,defaultobj) < 0) {
      return NULL;
    }
    return defaultobj;
  }

  if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) {
    if (insertion_resize(mp) < 0)
      return NULL;
  }

  Py_ssize_t ix = (mp->ma_keys->dk_lookup)(mp,&value);
  if (ix == DKIX_ERROR)
    return NULL;

  if (_PyDict_HasSplitTable(mp) &&
    ((ix >= 0 && value == NULL && mp->ma_used != ix) ||
     (ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) {
    if (insertion_resize(mp) < 0) {
      return NULL;
    }
    ix = DKIX_EMPTY;
  }

  if (ix == DKIX_EMPTY) {
    PyDictKeyEntry *ep,*ep0;
    value = defaultobj;
    if (mp->ma_keys->dk_usable <= 0) {
      if (insertion_resize(mp) < 0) {
        return NULL;
      }
    }
    Py_ssize_t hashpos = find_empty_slot(mp->ma_keys,hash);
    ep0 = DK_ENTRIES(mp->ma_keys);
    ep = &ep0[mp->ma_keys->dk_nentries];
    dictkeys_set_index(mp->ma_keys,mp->ma_keys->dk_nentries);
    Py_INCREF(key);
    Py_INCREF(value);
    MAINTAIN_TRACKING(mp,value);
    ep->me_key = key;
    ep->me_hash = hash;
    if (_PyDict_HasSplitTable(mp)) {
      assert(mp->ma_values[mp->ma_keys->dk_nentries] == NULL);
      mp->ma_values[mp->ma_keys->dk_nentries] = value;
    }
    else {
      ep->me_value = value;
    }
    mp->ma_used++;
    mp->ma_version_tag = DICT_NEXT_VERSION();
    mp->ma_keys->dk_usable--;
    mp->ma_keys->dk_nentries++;
    assert(mp->ma_keys->dk_usable >= 0);
  }
  else if (value == NULL) {
    value = defaultobj;
    assert(_PyDict_HasSplitTable(mp));
    assert(ix == mp->ma_used);
    Py_INCREF(value);
    MAINTAIN_TRACKING(mp,value);
    mp->ma_values[ix] = value;
    mp->ma_used++;
    mp->ma_version_tag = DICT_NEXT_VERSION();
  }

  ASSERT_CONSISTENT(mp);
  return value;
}

七、update(dict)

update()是把兩個字典合併成一個新的字典,中間有交叉的key,更新替換成新值,沒有交叉就直接建立

1、dict_update_common

static int
dict_update_common(PyObject *self,PyObject *args,PyObject *kwds,const char *methname)
{
  PyObject *arg = NULL;
  int result = 0;

  if (!PyArg_UnpackTuple(args,methname,&arg)) {
    result = -1;
  }
  else if (arg != NULL) {
    if (PyDict_CheckExact(arg)) {
      result = PyDict_Merge(self,arg,1);
    }
    else {
      _Py_IDENTIFIER(keys);
      PyObject *func;
      if (_PyObject_LookupAttrId(arg,&PyId_keys,&func) < 0) {
        result = -1;
      }
      else if (func != NULL) {
        Py_DECREF(func);
        result = PyDict_Merge(self,1);
      }
      else {
        result = PyDict_MergeFromSeq2(self,1);
      }
    }
  }

  if (result == 0 && kwds != NULL) {
    if (PyArg_ValidateKeywordArguments(kwds))
      result = PyDict_Merge(self,kwds,1);
    else
      result = -1;
  }
  return result;
}

2、dict_update

static PyObject *
dict_update(PyObject *self,PyObject *kwds)
{
  if (dict_update_common(self,args,"update") != -1)
    Py_RETURN_NONE;
  return NULL;
}

/* Update unconditionally replaces existing items.
  Merge has a 3rd argument 'override'; if set,it acts like Update,otherwise it leaves existing items unchanged.
  PyDict_{Update,Merge} update/merge from a mapping object.
  PyDict_MergeFromSeq2 updates/merges from any iterable object
  producing iterable objects of length 2.
*/

3、PyDict_Update

int
PyDict_Update(PyObject *a,PyObject *b)
{
  return dict_merge(a,b,1);
}

八、items()將字典轉換為列表

1、PyDict_Items

PyObject *
PyDict_Items(PyObject *mp)
{
  if (mp == NULL || !PyDict_Check(mp)) {
    PyErr_BadInternalCall();
    return NULL;
  }
  return dict_items((PyDictObject *)mp);
}

/* Return 1 if dicts equal,0 if not,-1 if error.
 * Gets out as soon as any difference is detected.
 * Uses only Py_EQ comparison.
 */

九、fromkeys(list,預設值)

1、_PyDict_FromKeys

/* Internal version of dict.from_keys(). It is subclass-friendly. */
PyObject *
_PyDict_FromKeys(PyObject *cls,PyObject *iterable,PyObject *value)
{
  PyObject *it;    /* iter(iterable) */
  PyObject *key;
  PyObject *d;
  int status;

  d = _PyObject_CallNoArg(cls);
  if (d == NULL)
    return NULL;

  if (PyDict_CheckExact(d) && ((PyDictObject *)d)->ma_used == 0) {
    if (PyDict_CheckExact(iterable)) {
      PyDictObject *mp = (PyDictObject *)d;
      PyObject *oldvalue;
      Py_ssize_t pos = 0;
      PyObject *key;
      Py_hash_t hash;

      if (dictresize(mp,ESTIMATE_SIZE(PyDict_GET_SIZE(iterable)))) {
        Py_DECREF(d);
        return NULL;
      }

      while (_PyDict_Next(iterable,&pos,&key,&oldvalue,&hash)) {
        if (insertdict(mp,value)) {
          Py_DECREF(d);
          return NULL;
        }
      }
      return d;
    }
    if (PyAnySet_CheckExact(iterable)) {
      PyDictObject *mp = (PyDictObject *)d;
      Py_ssize_t pos = 0;
      PyObject *key;
      Py_hash_t hash;

      if (dictresize(mp,ESTIMATE_SIZE(PySet_GET_SIZE(iterable)))) {
        Py_DECREF(d);
        return NULL;
      }

      while (_PySet_NextEntry(iterable,value)) {
          Py_DECREF(d);
          return NULL;
        }
      }
      return d;
    }
  }

  it = PyObject_GetIter(iterable);
  if (it == NULL){
    Py_DECREF(d);
    return NULL;
  }

  if (PyDict_CheckExact(d)) {
    while ((key = PyIter_Next(it)) != NULL) {
      status = PyDict_SetItem(d,value);
      Py_DECREF(key);
      if (status < 0)
        goto Fail;
    }
  } else {
    while ((key = PyIter_Next(it)) != NULL) {
      status = PyObject_SetItem(d,value);
      Py_DECREF(key);
      if (status < 0)
        goto Fail;
    }
  }

  if (PyErr_Occurred())
    goto Fail;
  Py_DECREF(it);
  return d;

Fail:
  Py_DECREF(it);
  Py_DECREF(d);
  return NULL;
}

2、dict_fromkeys_impl

static PyObject *
dict_fromkeys_impl(PyTypeObject *type,PyObject *value)
/*[clinic end generated code: output=8fb98e4b10384999 input=382ba4855d0f74c3]*/
{
  return _PyDict_FromKeys((PyObject *)type,iterable,value);
}

static int
dict_update_common(PyObject *self,1);
    else
      result = -1;
  }
  return result;
}

/* Note: dict.update() uses the METH_VARARGS|METH_KEYWORDS calling convention.
  Using METH_FASTCALL|METH_KEYWORDS would make dict.update(**dict2) calls
  slower,see the issue #29312. */

十、Clea清空字典

1、PyDict_ClearFreeList

int
PyDict_ClearFreeList(void)
{
  PyDictObject *op;
  int ret = numfree + numfreekeys;
  while (numfree) {
    op = free_list[--numfree];
    assert(PyDict_CheckExact(op));
    PyObject_GC_Del(op);
  }
  while (numfreekeys) {
    PyObject_FREE(keys_free_list[--numfreekeys]);
  }
  return ret;
}

2、PyDict_Clea

void
PyDict_Clear(PyObject *op)
{
  PyDictObject *mp;
  PyDictKeysObject *oldkeys;
  PyObject **oldvalues;
  Py_ssize_t i,n;

  if (!PyDict_Check(op))
    return;
  mp = ((PyDictObject *)op);
  oldkeys = mp->ma_keys;
  oldvalues = mp->ma_values;
  if (oldvalues == empty_values)
    return;
  /* Empty the dict... */
  dictkeys_incref(Py_EMPTY_KEYS);
  mp->ma_keys = Py_EMPTY_KEYS;
  mp->ma_values = empty_values;
  mp->ma_used = 0;
  mp->ma_version_tag = DICT_NEXT_VERSION();
  /* ...then clear the keys and values */
  if (oldvalues != NULL) {
    n = oldkeys->dk_nentries;
    for (i = 0; i < n; i++)
      Py_CLEAR(oldvalues[i]);
    free_values(oldvalues);
    dictkeys_decref(oldkeys);
  }
  else {
    assert(oldkeys->dk_refcnt == 1);
    dictkeys_decref(oldkeys);
  }
  ASSERT_CONSISTENT(mp);
}

3、dict_clear

static PyObject *
dict_clear(PyDictObject *mp,PyObject *Py_UNUSED(ignored))
{
  PyDict_Clear((PyObject *)mp);
  Py_RETURN_NONE;
}

4、dict_tp_clear

static int
dict_tp_clear(PyObject *op)
{
  PyDict_Clear(op);
  return 0;
}

更多關於Python字典新增,刪除,查詢等相關操作方法的文章請檢視下面的相關連結