python進階(第三章1) 字典

文章目錄

    • 3.1 泛映射類型
        • 什么是可散列的數據類型(鍵的要求)
        • 字典的構造方法
    • 3.2 字典推導(dictcomp)
    • 3.3 常見的映射方法
        • 用setdefault處理找不到的鍵
    • 3.4 映射的彈性鍵查詢
      • 3.4.1 defaultdict:處理找不到的鍵的一個選擇
        • 注意:
        • defaultdict與dict實例化字典類型的區別
        • defaultdict的構造
      • 3.4.2 特殊方法__missing__
    • 3.5 字典的變種
        • collections.OrderedDict (添加鍵會保持順序)
        • collections.ChainMap(將多個映射合并為單個映射)
        • collections.Counter
          • 例子:統計單詞中各個字母出現的次數
        • collections.UserDict
    • 3.6 子類化UserDict
      • MutableMapping.update
      • Mapping.get
        • 從dict或者其他內置類繼承有什么不好?
    • 3.7 不可變映射類型(動態的只讀的映射視圖:MappingProxyType)

3.1 泛映射類型

collections.abc模塊有Mapping和MutableMapping 這兩個抽象基類,它們的作用是為了dict和其他類似的類型定義形式接口,然后非抽象映射類型一般不會直接繼承這些抽象基類,它們會直接對dict或者collections.UserDict進行擴展。這些抽象基類的主要作用是作為形式化的文檔,它們定義了構建一個映射類型所需要的最基本的接口。然后它們還可以跟isinstance一起被用來判定某個數據是不是廣義上的映射類型:

>>> from collections import abc
>>> my_dict={}                    # 字典是典型的鍵值對
>>> isinstance(my_dict,abc.Mapping)
True                                
>>> isinstance([1, 2], abc.Mapping)
False									#列表時序列
>>> isinstance((1, 2), abc.Mapping)
False								#元組也是序列
>>> isinstance('sdbd', abc.Mapping)
False								#字符串也是序列
  • 這里用isintance而不是type來檢查某個參數是否為dict類型,因為這個參數有可能不是dict,而是一個比較另類的映射類型。(這句話不太明白)
  • 標準庫里的所有映射類型都是利用dict來實現的,因此它們有個共同的限制,即只有可散列的數據類型才可以用作這些映射里的鍵(只有鍵有這個要求,值沒有此要求)

什么是可散列的數據類型(鍵的要求)

如果一個對象是可散列的,那么在這個對象的生命周期中,它的散列值是不變的而且這個對象需要實現__hash__()方法。另外可散列對象還要有__eq__()方法,這樣才能和其他鍵作比較。如果兩個散列對象是相等的,那么它們的散列值一定是一樣
的。

可散列類型包括:

  • (1)原子不可變類型(str, bytes和數值類型)
  • (2)frozenset
  • (3)元組:只有當元組包含的所有元素都是可散列的情況下。
    可以用句話說:python里所有的不可變類型都是可散列的
    一般來講用戶自定義的類型的對象都是可散列的,散列值就是它們的id()函數的返回值。

字典的構造方法

>>> a= dict(one=1,two=2,three=3)
>>> b={'one':1,'two':2,'three':3}
>>> c= dict(zip(['one','two','three'],[1,2,3]))
>>> d = dict({'one':1,'two':2,'three':3})
>>> e=dict([('two',2),('one',1),('three',3)])
>>> a == b ==c == d == e
True
  • 注意這里的相等,只不過是值相等,但是不同的對象

3.2 字典推導(dictcomp)

列表生成器和生成器表達式的概念已經移植到了字典上,從而有了字典推導。
字典推導可以從任何鍵值對作為元素的可迭代對象中構建出字典。
例子:

>>> DIAL_CODES=[
... (86,'China'),
... (91,'India'),
... (1,'United States'),
... (62,'Indonesia'),
... (55,'Brazil'),
... (92,'Pakistan'),
... (880,'Bangladesh'),
... (234,'Nigeria'),
... (7,'Russia'),
... (81,'Japan'),
... ]
>>> country_code={country:code for code,country in DIAL_CODES}
>>> country_code
{'China': 86, 'India': 91, 'United States': 1, 'Indonesia': 62, 'Brazil': 55, 'Pakistan': 92, 'Bangladesh': 880, 'Nigeria': 234, 'Russia': 7, 'Japan': 81}
>>> {code:country.upper() for country,code in country_code.items() if code <66}
{1: 'UNITED STATES', 62: 'INDONESIA', 55: 'BRAZIL', 7: 'RUSSIA'}

字典推導的表達式會蔓延到其他數據結構類型

3.3 常見的映射方法

除了

  • dict
  • defaultdict
  • OrderedDict

這三種常見方法
在映射對象的方法里,setdefault可能是比較微妙的一個。盡管用的次數不多,但是它一旦發揮作用,就可以節省不少次鍵查詢,讓程序更高效。

用setdefault處理找不到的鍵

我們可以使用d.get(k,default)來代替d[k],給找不到的鍵一個默認的返回值(這比處理keyError方便不少)
看個例子:

>>> my_dict = {'子': '鼠', '丑': '牛', '寅': '虎',
...                '卯': '兔', '辰': '龍', '巳': '蛇',
...                '午': '馬', '未': '羊', '申': '猴',
...                '酉': '雞', '戌': '狗', '亥': '豬'}
>>> my_dict.setdefault('子','屬鼠')       # 顯然鍵 '子'存在,那么 值 '屬鼠' 也就無用
'鼠'
>>> my_dict.setdefault('行初心','CSDN')      # 如果找不到,就會添加.
'CSDN'
>>> my_dict.setdefault('行')    # 不存在的鍵"行",未指定值,默認返回None
>>> my_dict
{'子': '鼠', '丑': '牛', '寅': '虎', '卯': '兔', '辰': '龍', '巳': '蛇', '午': '馬', '未': '羊', '申': '猴', '酉': '雞', '戌': '狗', '亥': '豬', '行初心': 'CSDN', '行': None}

例子2:(使用dict.setdefault()方法來設置默認值,統計字符串出現的次數)

strings = ('puppy', 'kitten', 'puppy', 'puppy','weasel', 'puppy', 'kitten', 'puppy')
counts = {}
for kw in strings:counts.setdefault(kw, 0)counts[kw] += 1 

dict.setdefault()方法的返回值可以重寫for循環中的代碼,使其更加簡潔:

strings = ('puppy', 'kitten', 'puppy', 'puppy','weasel', 'puppy', 'kitten', 'puppy')
counts = {}
for kw in strings:counts[kw] = counts.setdefault(kw, 0) + 1

3.4 映射的彈性鍵查詢

為了方便,就算某個鍵在映射里不存在,那么你也希望在通過這個鍵讀取值的時候能得到一個默認值。有兩個途徑幫我們達到這個目的。

  • (1).通過defaultdict這個類型而不是普通的dict
  • (2).給自己定義一個dict類型的子類,然后在這個子類中實現__missing__方法。

3.4.1 defaultdict:處理找不到的鍵的一個選擇

在用戶創建defaultdict對象的時候,就需要給它配置一個為找不到的鍵創造默認值的方法。
具體而言,在實例化一個defaultdict的時候,需要給構造方法提供一個可調用的對象,這個可調用對象會在__getitem__碰到找不到的鍵的時候被調用,讓__getitem__返回某種默認值。
比如,新建一個字典:dd=defaultdict(list),如果鍵’new-key’在dd中不存在的話,表達式dd[‘new-key’]會按照以下步驟行事。

  • (1).調用list()來創建新列表
  • (2).把這個新列表作為值,'new-key’作為它的鍵,放到dd中。
  • (3).返回這個列表的引用
    而這個用來生成默認值的可調用對象存放在名為default_factory的實例屬性里。
    如果在創建defaultdict的時候沒有指定default_factory,查詢不存在的鍵會觸發KeyError.

注意:

  • defaultdict里面的default_factory只會在__getitem__里被調用,在其他的方法里完全不會發揮作用。比如,dd是個defaultdict,K是個找不到的鍵,dd[k]這個表達式會調用default_factory創造某個默認值,而dd.get(k)則會返回None.

所有 這一切背后的功臣其實是特殊方法__missing__.它會在defaultdict遇到找不到的鍵的時候調用default_factory,而實際上這個特性是所有映射類型都可以去選擇的。

看個例子:

from collections import defaultdict
class from_defaultdict(defaultdict):def __getitem__(self, key):return 'hello'c = from_defaultdict(list)print(c['new-key'])	

結果如下:
在這里插入圖片描述

defaultdict與dict實例化字典類型的區別

使用defaultdict任何未定義的key都會默認返回一個根據method_factory參數不同的默認值, 而相同情況下dict()會返回KeyError.
比較下面代碼:

from collections import defaultdict
d1 = dict()
d2 = defaultdict(list)
print(d2['a'])
print(d1['a'])

輸出:

[]
Traceback (most recent call last):File "/home/maxzhang/PycharmProjects/pythoncode/t.py", line 5, in <module>print(d1['a'])
KeyError: 'a'

defaultdict的構造

python官方文檔中對defaultdict的定義如下:

class collections.defaultdict([default_factory[, ...]])

python官方文檔中對defaultdict的解釋如下:

defaultdi:
dict subclass that calls a factory function to supply missing values
  • default_factory 接收一個工廠函數作為參數, 例如int str,list,set等.
  • defaultdict在dict的基礎上添加了一個__missing__(key)方法, 在調用一個不存的key的時候, defaultdict會調用__missing__, 返回一個根據default_factory參數的默認值, 所以不會返回Keyerror.

3.4.2 特殊方法__missing__

所有的映射類型在處理找不到的鍵的時候,都會牽扯到__missing__方法。這也是和這個方法稱作’missing’的原因。雖然基類dict并沒有定義這個方法,但是dict是知道有這么一個東西存在的。也就是說,如果有一個類繼承了dict,然后這個繼承類提供了__missing__方法,那么在__getitem__碰到找不到的鍵的時候,python會自動調用它。而不是拋出異常。

  • 注意:__missing__方法只會被__getitem__調用。提供__missing__方法對get或者__contains__這些方法的使用沒有影響。

如果要自定義一個映射類型,更合適的策略是繼承collections.UserDict類。

3.5 字典的變種

collections.OrderedDict (添加鍵會保持順序)

這個類型在添加鍵的時候會保持順序,因此鍵的迭代次序總是一致的。OrderedDict的popitem方法默認刪除并返回的是字典里的最后一個元素,但是如果像my_odict.popitem(last=False)這樣調用它,那么它刪除并返回第一個被添加進去的元素。
例子:

>>> d = collections.OrderedDict()
>>> d['a'] = 'A'
>>> d['b'] = 'B'
>>> d['c'] = 'C'
>>> for k ,v in d.items():
...     print(k,v)
... 
a A
b B
c C
>>> d.popitem(last=False)
('a', 'A')
>>> d
OrderedDict([('b', 'B'), ('c', 'C')])

collections.ChainMap(將多個映射合并為單個映射)

該類型可以容納數個不同的映射對象,然后在進行鍵查找操作的時候,這些對象會被當做一個整體逐個查找,直到鍵被找到為止。
例子:

>>> import collections
>>> a = {'x': 1, 'z': 3}
>>> b = {'y': 2, 'z': 4}
>>> c = collections.ChainMap(a, b)
>>> c['x']
1

collections.Counter

這個映射會給鍵準備一個整數計數器。每次更新一個鍵的時候都會增加這個基數器。所以這個類型可以用來給可散列表對象計數,或者是當成多重集來使用—多重集合就是集合里的元素可以出現不止一次。Counter實現了+和-運算符用來合并記錄,還有像most_common([n])這類很有用的方法。most_common([n])會按照次序返回映射里最常見的n個鍵和它們的計數。

例子:統計單詞中各個字母出現的次數
>>> ct = collections.Counter('afalfjlahgksdadaa')
>>> ct
Counter({'a': 6, 'f': 2, 'l': 2, 'd': 2, 'j': 1, 'h': 1, 'g': 1, 'k': 1, 's': 1})
>>> ct.update('aaaaaaaaadffdwe')
>>> ct
Counter({'a': 15, 'f': 4, 'd': 4, 'l': 2, 'j': 1, 'h': 1, 'g': 1, 'k': 1, 's': 1, 'w': 1, 'e': 1})
>>> ct.most_common(2)
[('a', 15), ('f', 4)]

collections.UserDict

這個類其實就是把標準dict用純python又實現了一遍
UserDict就是讓用戶繼承寫子類的。

3.6 子類化UserDict

就創造自定義映射類型來說,以UserDict為基類,總比以普通的dict為基類要來的方便。
更傾向于從UserDict而不是從dict繼承的主要原因是,后者有時會在某些方法的實現上走一些捷徑,導致我們不得不在它的子類中重寫這些方法,但是UserDict就不會帶來這些問題。
另外一個值得注意的地方是,UserDict并不是dict的子類,但是UserDict有一個叫做data的屬性是dict的實例,這個屬性就是UserDict最終存儲數據的地方。
例子:

import collectionsclass StrKeyDict(collections.UserDict):def __missing__(self, key):if isinstance(key,str):raise KeyErrorreturn self[str(key)]def __contains__(self, key):return str(key) in self.datadef __setitem__(self, key, item):self.data[str(key)] = item

因為UserDict 繼承的是MutableMapping,所以StrKeyDict里剩下的的那些映射類型的方法都是從UserDict,MutableMapping和Mapping這些超類繼承而來的。特別是最后的Mapping類,它雖然是一個抽象類(ABC),但是它提供了許多使用的方法。

MutableMapping.update

這個方法不但可以直接利用,它還用在__init__里,讓構造方法可以利用傳入的各種參數(其他映射類型,元素是(key,value)對的可迭代對象和鍵值參數)來新建實例。因為這個方法在背后是使用self[key]=value來添加新值的,所以它其實是在使用我們的__setitem__方法

Mapping.get

從dict或者其他內置類繼承有什么不好?

3.7 不可變映射類型(動態的只讀的映射視圖:MappingProxyType)

標準庫里所有的映射類型都是可變的,但是有時候你會有這樣的需求,比如不能讓用戶錯誤修改某個映射。

在types模塊中引入了一個封裝類名叫MappingProxyType。如果給這個類一個映射,它會返回一個動態的只讀的映射視圖。如果對原映射做出了修改,這個視圖可以觀察到,但是無法通過這個視圖對原映射進行修改。
例子:

>>> from types import MappingProxyType
>>> d = {1:'A'}
>>> d_proxy = MappingProxyType(d)
>>> d_proxy
mappingproxy({1: 'A'})
>>> d_proxy[1]                  #d中的內容可以通過d_proxy看到
'A'
>>> d_proxy[2] = 'x'          #但是d_proxy不能做任何的修改
Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: 'mappingproxy' object does not support item assignment
>>> d[2]= 'B'
>>> d_proxy                 #d_proxy是動態的,也就是說對d所做的任何改動都會反饋到它上面
mappingproxy({1: 'A', 2: 'B'})
>>> d_proxy[2]
'B'
>>> 

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/273832.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/273832.shtml
英文地址,請注明出處:http://en.pswp.cn/news/273832.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python基礎 list和tuple

文章目錄一、list1、len()函數可以獲得list元素的個數2、索引從0開始3、末尾追加 append(xx)4、也可以把元素插入到指定的位置&#xff0c;比如索引號為1的位置(insert)5、末尾刪除pop() &#xff0c;并且返回該值6、要刪除指定位置的元素&#xff0c;用pop(i)方法&#xff0c;…

HDU 2818 Building Block

題目連接 http://acm.hdu.edu.cn/showproblem.php?pid2818 題意:給定N個blocks&#xff0c;分在N個堆里&#xff0c;然后又P個操作&#xff0c;每次將x所在的堆放在y所在的堆上&#xff0c;或者詢問x的下面有幾個blocks 做法&#xff1a;帶權并查集 因為要查詢x的下面有多少bl…

百度社會化分享組件使用問題

今天下午玩了玩百度的社會化分享sdk,我是在這下載的sdk http://developer.baidu.com/frontia/sdk 誰知道這個下載鏈接是沒更新的,還是1.0版本的,是尼瑪13年初的版本 搗鼓了半天各種bug 然后去百度官網重新找http://developer.baidu.com/wiki/index.php?titledocs/frontia/res…

python基礎 dict和set

文章目錄dictset4.用集合為列表去重5.集合的增 add,update6.集合的刪 discard,remove,pop,clear7 集合運算7.1 子集(<或者issubset()方法)7.2并集(|或者union()方法)7.3 交集(&或者intersection())7.4 差集(-或者difference()方法)7.5 對稱集(^或者symmetric_difference…

python進階(第三章2)字典和集合

文章目錄3.8 集合論nee中的元素在haystack中出現的次數&#xff0c;可以在任何可迭代對象上3.8.1集合字面量3.8.2 集合推導3.8.3 集合操作3.9 dict和set的背后3.9.1 一個關于效率的實驗3.9.2 字典中的散列表1.散列值和相等性2.散列表算法獲取值&#xff1a;添加新的元素更新現有…

Android下實現GPS定位服務

1.申請Google API Key&#xff0c;參考前面文章 2.實現GPS的功能需要使用模擬器進行經緯度的模擬設置&#xff0c;請參考前一篇文章進行設置 3.創建一個Build Target為Google APIs的項目 4.修改Androidmanifest文件&#xff1a; view plain<uses-library android:name"…

python 鏈表 【測試題】

文章目錄注意&#xff1a;實例講解1 .鏈表基本功能2. 根據值刪除鏈表中的節點信息答案&#xff1a;3.反轉一個單鏈表信息答案4.合并兩個有序鏈表信息答案5.刪除排序鏈表中的重復元素信息答案6.移除鏈表元素信息7.環形鏈表信息進階思路答案注意&#xff1a; 這里的head是只存儲…

WebService應用一例,帶有安全驗證

1、創建WEB項目&#xff0c;添加WEB服務WebService1.asmx&#xff0c;代碼如下&#xff1a; 1 using System;2 using System.Collections.Generic;3 using System.Linq;4 using System.Web;5 using System.Web.Services;6 7 namespace WebService8 {9 /// <summary> …

linux集成開發環境

Linux操作系統的種種集成開發環境隨著Linux的逐漸興起&#xff0c;已經有為數眾多的程序在上面馳騁了&#xff0c;許多開發環境(Development Environment)也應運而生。好的開發環境一定是集成了編輯、編譯和調試等多項功能并且易于使用。本文介紹了一些在Linux上流行的開發環境…

mysql技術內幕《讀書筆記》

文章目錄1. mysql 體系結構和存儲引擎1.5 連接mysql1.5.11. mysql 體系結構和存儲引擎 1.5 連接mysql 連接mysql操作是一個連接進程和mysql數據庫實例進行通信。 本質是進程通信&#xff0c;常用的進程通信方式有管道&#xff0c;命名管道&#xff0c;命名字&#xff0c;TCP/…

DEDECMS全版本gotopage變量XSS ROOTKIT 0DAY

影響版本&#xff1a; DEDECMS全版本 漏洞描敘&#xff1a; DEDECMS后臺登陸模板中的gotopage變量未效驗傳入數據&#xff0c;導致XSS漏洞。 \dede\templets\login.htm 65行左右 <input type"hidden" name"gotopage" value"<?php if(!empty($g…

Android開源庫loopj的android-async-http的 JsonHttpResponseHandler 存在死循環GC_CONCURRENT

我現在用的是 AndroidAsyncHttp 1.4.4 版本&#xff0c;之前遇到一個很奇怪的問題&#xff0c; 當使用 JsonHttpResponseHandler 解析請求的頁面出現服務器錯誤或其他情況返回的內容不是 JSON 字符串時不會調用自己復寫實現的 onSuccess 或者 onFailure 方法&#xff0c;將會出…

python【進階】4.文本和字節序列

文章目錄1. 字符、碼位和字節表述4.1字符問題2. bytes、bytearray 和 memoryview 等二進制序列的獨特特性3. 全部 Unicode 和陳舊字符集的編解碼器4.避免和處理編碼錯誤5.處理文本文件的最佳實踐6.默認編碼的陷阱和標準 I/O 的問題7.規范化 Unicode 文本,進行安全的比較8.規范化…

C#序列化和反序列化

序列化和反序列化我們可能經常會聽到&#xff0c;其實通俗一點的解釋&#xff0c;序列化就是把一個對象保存到一個文件或數據庫字段中去&#xff0c;反序列化就是在適當的時候把這個文件再轉化成原來的對象使用。我想最主要的作用有&#xff1a; 1、在進程下次啟動時讀取上次保…

python【進階】5.一等函數(注銷)

在 Python 中,函數是一等對象。編程語言理論家把“一等對象”定義為滿足下述條件的程 序實體: 在運行時創建能賦值給變量或數據結構中的元素能作為參數傳給函數能作為函數的返回結果 在 Python 中,所有函數都是一等對象。 5.1 把函數視作對象 >>> def d(n): ... …

進程狀態轉換(了解)

進程三個基本狀態&#xff1a;就緒、阻塞、運行 這個比較簡單&#xff0c;進程創建后進入就緒狀態、然后若CPU空閑或能打斷CPU正在執行的進程&#xff08;優先級低的&#xff09;&#xff0c;那么就緒狀態轉換成運行態&#xff0c;運行時&#xff0c;進程需要用到其他資源&…

rebuild online意外終止導致ora-8104錯誤的實驗

rebuild online意外終止導致ora-8104錯誤的實驗 SQL> !oerr ora 810408104, 00000, "this index object %s is being online built or rebuilt"// *Cause: the index is being created or rebuild or waited for recovering // from the online (re)build // *Act…

關于range方法,如果你覺得python很簡單就錯了

前言&#xff1a;在系統學習迭代器之前&#xff0c;我一直以為 range() 方法也是用于生成迭代器的&#xff0c;現在卻突然發現&#xff0c;它生成的只是可迭代對象&#xff0c;而并不是迭代器&#xff01; 1、range() 是什么&#xff1f; 對于 range() 函數&#xff0c;有幾個注…

centos下crontab的使用

1.作用使用crontab命令可以修改crontab配置文件&#xff0c;然后該配置由cron公用程序在適當的時間執行&#xff0c;該命令使用權限是所有用戶。2.格式crontab [-u user] {-l | -r | -e}3.crontab命令選項: -u指定一個用戶, -l列出某個用戶的任務計劃, -r刪除某個用戶的任務, -…

關于python3中的包operator(支持函數式編程的包)

文章目錄1.functools2.operator.itemgetter3.operator.attrgetter雖然 Guido 明確表明,Python 的目標不是變成函數式編程語言,但是得益于 operator 和 functools 等包的支持,函數式編程風格也可以信手拈來。接下來的兩節分別介紹這兩 個包。 1.functools 示例1 使用 reduce 函…