Python defaultdict 模塊和 namedtuple 模塊

在Python中有一些內(nèi)置的數(shù)據(jù)類型抽兆,比如int, str, list, tuple, dict等磕蛇。Python的collections模塊在這些內(nèi)置數(shù)據(jù)類型的基礎(chǔ)上,提供了幾個(gè)額外的數(shù)據(jù)類型:namedtuple, defaultdict, deque, Counter, OrderedDict等锋八,其中defaultdict和namedtuple是兩個(gè)很實(shí)用的擴(kuò)展類型磺浙。defaultdict繼承自dict,namedtuple繼承自tuple跑慕。

一万皿、defaultdict

1. 簡(jiǎn)介

在使用Python原生的數(shù)據(jù)結(jié)構(gòu)dict的時(shí)候,如果用d[key]這樣的方式訪問,當(dāng)指定的key不存在時(shí)相寇,是會(huì)拋出KeyError異常的慰于。但是,如果使用defaultdict唤衫,只要你傳入一個(gè)默認(rèn)的工廠方法婆赠,那么請(qǐng)求一個(gè)不存在的key時(shí), 便會(huì)調(diào)用這個(gè)工廠方法使用其結(jié)果來(lái)作為這個(gè)key的默認(rèn)值佳励。

defaultdict在使用的時(shí)候需要傳一個(gè)工廠函數(shù)(function_factory)休里,defaultdict(function_factory)會(huì)構(gòu)建一個(gè)類似dict的對(duì)象,該對(duì)象具有默認(rèn)值赃承,默認(rèn)值通過調(diào)用工廠函數(shù)生成妙黍。

2. 示例

下面給一個(gè)defaultdict的使用示例:

>>> from collections import defaultdict
>>> s = [('xiaoming', 99), ('wu', 69), ('zhangsan', 80), ('lisi', 96), ('wu', 100), ('wu', 100), ('yuan', 98), ('xiaoming', 89)]
>>> d = defaultdict(list)
>>> for k, v in s:
...     d[k].append(v)
... 
>>> d
defaultdict(<type 'list'>, {'lisi': [96], 'xiaoming': [99, 89], 'yuan': [98], 'zhangsan': [80], 'wu': [69, 100, 100]})
>>> for k,v in d.items():
...     print '%s: %s' % (k, v)
... 
lisi: [96]
xiaoming: [99, 89]
yuan: [98]
zhangsan: [80]
wu: [69, 100, 100]
>>> 

對(duì)Python比較熟悉的同學(xué)可以發(fā)現(xiàn)defaultdict(list)的用法和dict.setdefault(key, [])比較類似,上述代碼使用setdefault實(shí)現(xiàn)如下:

>>> s
[('xiaoming', 99), ('wu', 69), ('zhangsan', 80), ('lisi', 96), ('wu', 100), ('wu', 100), ('yuan', 98), ('xiaoming', 89)]
>>> d = {}
>>> for k,v in s:
...     d.setdefault(k, []).append(v)
... 
>>> d
{'lisi': [96], 'xiaoming': [99, 89], 'yuan': [98], 'zhangsan': [80], 'wu': [69, 100, 100]}

3. 原理

從以上的例子中瞧剖,我們可以基本了解了defaultdict的用法拭嫁,下面我們可以通過help(defaultdict)了解一下defaultdict的原理。通過Python console打印出的help信息來(lái)看抓于,我們可以發(fā)現(xiàn)defaultdict具有默認(rèn)值主要是通過missing方法實(shí)現(xiàn)的做粤,如果工廠函數(shù)不為None,則通過工廠方法返回默認(rèn)值捉撮,具體如下:

>>> help(defaultdict)
 |  __missing__(...)
 |      __missing__(key) # Called by __getitem__ for missing key; pseudo-code:
 |      if self.default_factory is None: raise KeyError((key,))
 |      self[key] = value = self.default_factory()
 |      return value

從上面的說(shuō)明中怕品,我們可以發(fā)現(xiàn)一下幾個(gè)需要注意的地方:

  1. missing方法是在調(diào)用getitem方法發(fā)現(xiàn)KEY不存在時(shí)才調(diào)用的,所以巾遭,defaultdict也只會(huì)在使用d[key]或者d.getitem(key)的時(shí)候才會(huì)生成默認(rèn)值肉康;如果使用d.get(key)是不會(huì)返回默認(rèn)值的,會(huì)出現(xiàn)KeyError灼舍;

  2. defaultdict主要是通過missing方法實(shí)現(xiàn)吼和,所以,我們也可以通過實(shí)現(xiàn)該方法來(lái)生成自己的defaultdict

4. 版本

defaultdict是在Python 2.5之后才加入的功能骑素,在舊版本的Python中是不支持這個(gè)功能的炫乓,不過,知道了它的原理砂豌,我們可以自己實(shí)現(xiàn)一個(gè)defaultdict厢岂。

try:
    from collections import defaultdict
except:
    class defaultdict(dict):

        def __init__(self, default_factory=None, *a, **kw):
            if (default_factory is not None and not hasattr(default_factory, '__call__')):
                raise TypeError('first argument must be callable')
            dict.__init__(self, *a, **kw)
            self.default_factory = default_factory

        def __getitem__(self, key):
            try:
                return dict.__getitem__(self, key)
            except KeyError:
                return self.__missing__(key)

        def __missing__(self, key):
            if self.default_factory is None:
                raise KeyError(key)
            self[key] = value = self.default_factory()
            return value

        def __reduce__(self):
            if self.default_factory is None:
                args = tuple()
            else:
                args = self.default_factory,
            return type(self), args, None, None, self.items()

        def copy(self):
            return self.__copy__()

        def __copy__(self):
            return type(self)(self.default_factory, self)

        def __deepcopy__(self, memo):
            import copy
            return type(self)(self.default_factory, copy.deepcopy(self.items()))

        def __repr__(self):
            return 'defaultdict(%s, %s)' % (self.default_factory, dict.__repr__(self))

二光督、namedtuple

namedtuple主要用來(lái)產(chǎn)生可以使用名稱來(lái)訪問元素的數(shù)據(jù)對(duì)象阳距,通常用來(lái)增強(qiáng)代碼的可讀性,在訪問一些tuple類型的數(shù)據(jù)時(shí)尤其好用结借。其實(shí)筐摘,在大部分時(shí)候你應(yīng)該使用namedtuple替代tuple,這樣可以讓你的代碼更容易讀懂,更加pythonic咖熟。舉個(gè)例子:

from collections import namedtuple

# 變量名和namedtuple中的第一個(gè)參數(shù)一般保持一致圃酵,但也可以不一樣
Student = namedtuple('Student', 'id name score')
# 或者 Student = namedtuple('Student', ['id', 'name', 'score'])

students = [(1, 'Wu', 90), (2, 'Xing', 89), (3, 'Yuan', 98), (4, 'Wang', 95)]

for s in students:
    stu = Student._make(s)
    print stu

# Output:
# Student(id=1, name='Wu', score=90)
# Student(id=2, name='Xing', score=89)
# Student(id=3, name='Yuan', score=98)
# Student(id=4, name='Wang', score=95)

在上面的例子中,Student就是一個(gè)namedtuple馍管,它和tuple的使用方法一樣郭赐,可以通過index直接取,而且是只讀的确沸。這種方式比tuple容易理解多了捌锭,可以很清楚的知道每個(gè)值代表的含義。

Over!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末罗捎,一起剝皮案震驚了整個(gè)濱河市观谦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桨菜,老刑警劉巖豁状,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異倒得,居然都是意外死亡泻红,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門屎暇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)承桥,“玉大人,你說(shuō)我怎么就攤上這事根悼⌒滓欤” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵挤巡,是天一觀的道長(zhǎng)剩彬。 經(jīng)常有香客問我,道長(zhǎng)矿卑,這世上最難降的妖魔是什么喉恋? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮母廷,結(jié)果婚禮上轻黑,老公的妹妹穿的比我還像新娘。我一直安慰自己琴昆,他們只是感情好氓鄙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著业舍,像睡著了一般抖拦。 火紅的嫁衣襯著肌膚如雪升酣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天态罪,我揣著相機(jī)與錄音噩茄,去河邊找鬼。 笑死复颈,一個(gè)胖子當(dāng)著我的面吹牛绩聘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播耗啦,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼君纫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了芹彬?” 一聲冷哼從身側(cè)響起蓄髓,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎舒帮,沒想到半個(gè)月后会喝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡玩郊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年肢执,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片译红。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡预茄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出侦厚,到底是詐尸還是另有隱情耻陕,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布刨沦,位于F島的核電站诗宣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏想诅。R本人自食惡果不足惜召庞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望来破。 院中可真熱鬧篮灼,春花似錦、人聲如沸徘禁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)晌坤。三九已至逢艘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間骤菠,已是汗流浹背它改。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留商乎,地道東北人央拖。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鹉戚,于是被迫代替她去往敵國(guó)和親鲜戒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容