Python3 CookBook學(xué)習(xí)筆記 -- 數(shù)據(jù)結(jié)構(gòu)與算法

1. 迭代對象解壓賦值

解壓賦值操作可以應(yīng)用到任何迭代對象上丛肢,如:列表元組剿干、字符串蜂怎、文件對象迭代器置尔、生成器杠步。

唯一的要求:

  • 變量的數(shù)量必須跟序列元素的數(shù)量是一樣的。
>>> p=(1,2,3,4)
>>> a,b,c,d=p
>>> a
1
>>> b
2
>>> c
3
>>> d
4
>>> datas=['apple', 'cherry', 1, (1,2,3,4)]
>>> a,b,c,d=datas
>>> a
'apple'
>>> b
'cherry'
>>> c
1
>>> d
(1, 2, 3, 4)
>>> s='faris'
>>> a,b,c,d,e=s
>>> a
'f'
>>> b
'a'
>>> c
'r'
>>> d
'i'
>>> e
's'

2. 擴(kuò)展迭代對象解壓賦值

如果遇到不確定個(gè)數(shù)或任意個(gè)數(shù)元素的可迭代對象時(shí)榜轿,則需要使用星號表達(dá)式可以用來解決這個(gè)問題幽歼。

假設(shè)你現(xiàn)在有一些用戶的記錄列表,每條記錄包含一個(gè)名字谬盐、郵件甸私,接著就是不確定數(shù)量的電話號碼。

>>> record = ('Dave', 'dave@example.com', '773-555-1212', '847-555-1212')
>>> name, email, *phone_numbers = record
>>> name
'Dave'
>>> email
'dave@example.com'
>>> phone_numbers
['773-555-1212', '847-555-1212']
>>>

如果你想解壓一些元素后丟棄它們设褐,你不能簡單就使用 * 颠蕴, 但是你可以使用一個(gè)普通的廢棄名稱,比如 _ 或者 ign (ignore)助析。

>>> record = ('ACME', 50, 123.45, (12, 18, 2012))
>>> name, *_, (*_, year) = record
>>> 
>>> 
>>> 
>>> name
'ACME'
>>> _
[12, 18]
>>> 
>>> 
>>> year
2012

3. 查找最大或最小的 N 個(gè)元素

heapq 模塊有兩個(gè)函數(shù):nlargest()nsmallest() 可以完美解決這個(gè)問題犀被。

輸出最大和最小的三個(gè)值:

>>> import heapq
>>> nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
>>> print(heapq.nlargest(3, nums)) 
[42, 37, 23]
>>> print(heapq.nsmallest(3, nums))
[-4, 1, 2]

兩個(gè)函數(shù)都能接受一個(gè)關(guān)鍵字參數(shù),用于更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)中:

>>> portfolio = [
...     {'name': 'IBM', 'shares': 100, 'price': 91.1},
...     {'name': 'AAPL', 'shares': 50, 'price': 543.22},
...     {'name': 'FB', 'shares': 200, 'price': 21.09},
...     {'name': 'HPQ', 'shares': 35, 'price': 31.75},
...     {'name': 'YHOO', 'shares': 45, 'price': 16.35},
...     {'name': 'ACME', 'shares': 75, 'price': 115.65}
... ]
>>> cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
>>> expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])
>>> 
>>> cheap
[{'name': 'YHOO', 'shares': 45, 'price': 16.35}, {'name': 'FB', 'shares': 200, 'price': 21.09}, {'name': 'HPQ', 'shares': 35, 'price': 31.75}]
>>> 
>>> expensive
[{'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'ACME', 'shares': 75, 'price': 115.65}, {'name': 'IBM', 'shares': 100, 'price': 91.1}]

注意點(diǎn)

  • 當(dāng)要查找的元素個(gè)數(shù)相對比較小的時(shí)候外冀,函數(shù) nlargest()nsmallest() 是很合適的寡键。

  • 如果你僅僅想查找唯一的最小或最大(N=1)的元素的話,那么使用 min()max() 函數(shù)會(huì)更快些雪隧。

  • 如果 N 的大小和集合大小接近的時(shí)候西轩,通常先排序這個(gè)集合然后再使用切片操作會(huì)更快點(diǎn) ( sorted(items)[:N] 或者是 sorted(items)[-N:] )。

4. 實(shí)現(xiàn)一個(gè)優(yōu)先級隊(duì)列

import heapq

class PriorityQueue:
    def __init__(self):
        self._queue = []
        self._index = 0

    def push(self, item, priority):
        heapq.heappush(self._queue, (-priority, self._index, item))
        self._index += 1

    def pop(self):
        return heapq.heappop(self._queue)[-1]



class Item:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
     return 'Item({!r})'.format(self.name)


q = PriorityQueue()
q.push(Item('foo'), 1)
q.push(Item('bar'), 5)
q.push(Item('spam'), 4)
q.push(Item('grok'), 1)

q.pop()
q.pop()
q.pop()
q.pop()

在上面代碼中脑沿,隊(duì)列包含了一個(gè) (-priority, index, item) 的元組藕畔。 優(yōu)先級為負(fù)數(shù)的目的是使得元素按照優(yōu)先級從高到低排序。 這個(gè)跟普通的按優(yōu)先級從低到高排序的堆排序恰巧相反庄拇。

對于Item對象是不支持相互比較的:

>>> a=Item('foo')
>>> b=Item('boo')
>>> a > b
Traceback (most recent call last):
  File "test.py", line 26, in <module>
    a > b
TypeError: '>' not supported between instances of 'Item' and 'Item'

但是使用元組注服,則可以進(jìn)行比較:

>>> class Item:
...     def __init__(self, name):
...             self.name = name
...     def __repr__(self):
...      return 'Item({!r})'.format(self.name)
... 
>>> 
>>> a=(1, Item('foo'))
>>> b=(2, Item('boo'))
>>> print (a > b)
False

5. 字典中的鍵映射多個(gè)值 multidict

一個(gè)字典就是一個(gè)鍵對應(yīng)一個(gè)單值的映射韭邓。如果你想要一個(gè)鍵映射多個(gè)值,那么你就需要將這多個(gè)值放到另外的容器中溶弟, 比如列表或者集合里面女淑。

d = {
    'a' : [1, 2, 3],
    'b' : [4, 5]
}
e = {
    'a' : {1, 2, 3},
    'b' : {4, 5}
}

使用 collections 模塊中的 defaultdict 來構(gòu)造一鍵多值的字典:

>>> from collections import defaultdict
>>> 
>>> d = defaultdict(list)
>>> d['a'].append(1)
>>> d['a'].append(2)
>>> d['b'].append(4)
>>> 
>>> d = defaultdict(set)
>>> d['a'].add(1)
>>> d['a'].add(2)
>>> d['b'].add(4)
>>> 
>>> d
defaultdict(<class 'set'>, {'a': {1, 2}, 'b': {4}})

defaultdict 會(huì)自動(dòng)為將要訪問的鍵(就算目前字典中并不存在這樣的鍵)創(chuàng)建映射實(shí)體。

>>> d = defaultdict(set)
>>> 
>>> 
>>> d['d']
set()
>>> d
defaultdict(<class 'set'>, {'d': set()})

可以通過一個(gè)普通的字典上使用 setdefault() 去除這個(gè)情況:

>>> d = {}
>>> d.setdefault('a', []).append(1)
>>> d.setdefault('a', []).append(2)
>>> d.setdefault('b', []).append(4)
>>> 
>>> d
{'a': [1, 2], 'b': [4]}
>>> d['c']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'c'
>>> 
>>> d['a']
[1, 2]

這種寫法是讓人非常別扭的辜御,因?yàn)樾枰嘈┮淮?code>[]鸭你。

也可以自己實(shí)現(xiàn):

d = {}
for key, value in pairs:
    if key not in d:
        d[key] = []
    d[key].append(value)

但是從Python提倡的簡潔上來說,沒有defaultdict簡潔:

d = defaultdict(list)
for key, value in pairs:
    d[key].append(value)

6. 字典按順序輸出

為了能控制一個(gè)字典中元素的順序擒权,你可以使用 collections 模塊中的 OrderedDict

>>> from collections import OrderedDict
>>> 
>>> d = OrderedDict()
>>> d['foo'] = 1
>>> d['bar'] = 2
>>> d['spam'] = 3
>>> d['grok'] = 4
>>> 
>>> d
OrderedDict([('foo', 1), ('bar', 2), ('spam', 3), ('grok', 4)])
>>> 
>>> for key in d:
...     print(key, d[key])
... 
foo 1
bar 2
spam 3
grok 4

OrderedDict 內(nèi)部維護(hù)著一個(gè)根據(jù)鍵插入順序排序的雙向鏈表袱巨。每次當(dāng)一個(gè)新的元素插入進(jìn)來的時(shí)候姊途, 它會(huì)被放到鏈表的尾部萧落。

一個(gè) OrderedDict 的大小是一個(gè)普通字典的兩倍胆胰,因?yàn)樗鼉?nèi)部維護(hù)著另外一個(gè)鏈表蝠猬。 大量數(shù)據(jù)時(shí)陕截,需要權(quán)衡效率果元。

7. 字典運(yùn)算

如何在數(shù)據(jù)字典中 執(zhí)行 求最小值丹喻、最大值椒惨、排序贱鄙?

上面我們學(xué)習(xí)的方法為:

  • 使用heapq 中的 nlargest劝贸、nsmallestheapify完成堆排序逗宁。

  • 使用 sorted函數(shù)映九。

  • 使用 min函數(shù) 和 max函數(shù)

參考股票名和價(jià)格映射字典:

prices = {
    'ACME': 45.23,
    'AAPL': 612.78,
    'IBM': 205.55,
    'HPQ': 37.20,
    'FB': 10.75
}

7.1 heapq

顯然無法實(shí)現(xiàn)字典排序,無論是根據(jù)key排序瞎颗,還是根據(jù)value排序件甥。

>>> heapq.nlargest(1, prices)
['IBM']
>>> heapq.nsmallest(1, prices)
['AAPL']
>>> heapq.heapify(prices)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: heap argument must be a list

7.2 sorted

顯然 sorted無法實(shí)現(xiàn)對value的排序,只能對key進(jìn)行排序并返回排好序的key列表哼拔,且還需要再次遍歷這個(gè)列表才能獲取value引有。

>>> sorted(prices)
['AAPL', 'ACME', 'FB', 'HPQ', 'IBM']

7.2 min max

顯然和sorted是相同的問題,只能對key進(jìn)行排序倦逐。

>>> min(prices)
'AAPL'
>>> 
>>> 
>>> max(prices)
'IBM'

方案1 zip:

我們?yōu)榱藢χ颠M(jìn)行操作時(shí)譬正,需要使用zip() 函數(shù)對keyvalue進(jìn)行翻轉(zhuǎn)。

>>> list(zip(prices.values(), prices.keys()))
[(45.23, 'ACME'), (612.78, 'AAPL'), (205.55, 'IBM'), (37.2, 'HPQ'), (10.75, 'FB')]
>>> 
>>> 
>>> min(zip(prices.values(), prices.keys()))
(10.75, 'FB')
>>> 
>>> 
>>> max(zip(prices.values(), prices.keys()))
(612.78, 'AAPL')
>>> 
>>> 
>>> sorted(zip(prices.values(), prices.keys()))
[(10.75, 'FB'), (37.2, 'HPQ'), (45.23, 'ACME'), (205.55, 'IBM'), (612.78, 'AAPL')]

需要注意的是 zip() 函數(shù)創(chuàng)建的是一個(gè)只能訪問一次的迭代器檬姥。

>>> prices_and_names = zip(prices.values(), prices.keys())
>>> print(min(prices_and_names)) # OK
(10.75, 'FB')
>>> print(max(prices_and_names))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: max() arg is an empty sequence

方案2 min + values max + values

直接輸出最大或者最小values

>>> min(prices.values()) # Returns 10.75
10.75
>>> max(prices.values()) # Returns 612.78
612.78

輸出最大或者最小的value對應(yīng)的key

>>> min(prices, key=lambda k: prices[k]) 
'FB'
>>> max(prices, key=lambda k: prices[k]) 
'AAPL'

8. 查找兩字典的相同點(diǎn)

怎樣在兩個(gè)字典中尋尋找相同點(diǎn)(比如相同的鍵曾我、相同的值等等)?

a = {
    'x' : 1,
    'y' : 2,
    'z' : 3
}

b = {
    'w' : 10,
    'x' : 11,
    'y' : 2
}

最直接的想法便是遍歷a健民,然后檢查b抒巢。

python其實(shí)更加簡單方便

相同的key

>>> a.keys() & b.keys()
{'y', 'x'}

a中有,b中沒有的key

>>> a.keys() - b.keys()
{'z'}

相同的元素

>>> a.items() & b.items()
{('y', 2)}

兩個(gè)字典的合集

>>> a.items() | b.items()
{('x', 11), ('z', 3), ('y', 2), ('w', 10), ('x', 1)}

我們可以使用以上的操作秉犹,來完成修改或者過濾字典元素虐秦。

>>> c = {key:a[key] for key in a.keys() - {'z', 'w'}}
>>> 
>>> 
>>> c
{'y': 2, 'x': 1}

一個(gè)字典就是一個(gè)鍵集合與值集合的映射關(guān)系平酿。 字典的 keys() 方法返回一個(gè)展現(xiàn)鍵集合的鍵視圖對象。 鍵視圖的一個(gè)很少被了解的特性就是它們也支持集合操作悦陋,比如集合并、交筑辨、差運(yùn)算俺驶。 所以,如果你想對集合的鍵執(zhí)行一些普通的集合操作棍辕,可以直接使用鍵視圖對象而不用先將它們轉(zhuǎn)換成一個(gè) set暮现。

>>> type(a.keys())
<class 'dict_keys'>
>>> 
>>> 
>>> type(a.keys() & b.keys())
<class 'set'>

字典的 items() 方法返回一個(gè)包含 (鍵,值) 對的元素視圖對象楚昭。 這個(gè)對象同樣也支持集合操作栖袋,并且可以被用來查找兩個(gè)字典有哪些相同的鍵值對。

>>> type(a.items())
<class 'dict_items'>
>>> 
>>> 
>>> type(a.items() & b.items())
<class 'set'>

盡管字典的 values() 方法也是類似抚太,但是它并不支持這里介紹的集合操作塘幅。 某種程度上是因?yàn)橹狄晥D不能保證所有的值互不相同,這樣會(huì)導(dǎo)致某些集合操作會(huì)出現(xiàn)問題尿贫。 不過电媳,如果你硬要在值上面執(zhí)行這些集合操作的話,你可以先將值集合轉(zhuǎn)換成 set庆亡,然后再執(zhí)行集合運(yùn)算就行了匾乓。

>>> 
>>> type(a.values())
<class 'dict_values'>
>>> 
>>> 
>>> a.values() & b.values()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'dict_values' and 'dict_values'
>>> 
>>> 
>>> set(a.values()) & set(b.values())
{2}

9. 刪除序列相同元素并保持順序

怎樣在一個(gè)序列上面保持元素順序的同時(shí)消除重復(fù)的值?

如果序列上的值都是 hashable類型又谋,那么可以很簡單的利用集合或者生成器來解決這個(gè)問題拼缝。

什么是 hashable類型?

An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() method). Hashable objects which compare equal must have the same hash value. Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.

如果一個(gè)對象在其生命周期內(nèi)有一個(gè)固定不變的哈希值 (這需要__hash__() 方法) 彰亥,且可以與其他對象進(jìn)行比較操作 (這需要__eq__() 方法) 咧七,那么這個(gè)對象就是可哈希對象 ( hashable ) ∈@ⅲ可哈希對象必須有相同的哈希值才算作相等猪叙。 由于字典 ( dict ) 的鍵 ( key ) 和集合 ( set ) 內(nèi)部使用到了哈希值,所以只有可哈希 ( hashable ) 對象才能被用作字典的鍵和集合的元素仁卷。 所有 python 內(nèi)置的不可變對象都是可哈希的穴翩,同時(shí),可變?nèi)萜?(比如:列表 ( list ) 或者字典 ( dict ) ) 都是不可哈希的锦积。用戶自定義的類的實(shí)例默認(rèn)情況下都是可哈希的芒帕;它們跟其它對象都不相等 (除了它們自己) ,它們的哈希值來自 id() 方法丰介。

>>> 
>>> def dedupe(items):
...     seen = set()
...     for item in items:
...         if item not in seen:
...             yield item
...             seen.add(item)
...     return items
... 
>>> a = [1, 5, 2, 1, 9, 1, 5, 10]
>>> 
>>> list(dedupe(a))
[1, 5, 2, 9, 10]

這個(gè)方法僅僅在序列中元素為 hashable 的時(shí)候才管用背蟆。 如果你想消除元素不可哈希(比如 dict 類型)的序列中重復(fù)元素的話鉴分,你需要將上述代碼稍微改變一下,就像這樣:

>>> def dedupe(items, key=None):
...     seen = set()
...     for item in items:
...         val = item if key is None else key(item)
...         if val not in seen:
...             yield item
...             seen.add(val)
...     return items
... 
>>> 
>>> a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
>>> 
>>> list(dedupe(a, key=lambda d: (d['x'],d['y'])))
[{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]
>>> 
>>> 
>>> list(dedupe(a, key=lambda d: d['x']))
[{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]

如果你僅僅就是想消除重復(fù)元素而不用維持順序的話带膀,通持菊洌可以簡單的構(gòu)造一個(gè)集合

>>> a=[1, 5, 2, 1, 9, 1, 5, 10]
>>> list(set(a))
[1, 2, 5, 9, 10]

如果我們想讀取文件并排除掉重復(fù)行,也可以使用上面的方法

with open(somefile,'r') as f:
for line in dedupe(f):
    ...

10. 命名切片

假定你有一段代碼要從一個(gè)記錄字符串中幾個(gè)固定位置提取出特定的數(shù)據(jù)字段(比如文件或類似格式):

>>> record = '....................100 .......513.25 ..........'
>>> cost = int(record[20:23]) * float(record[31:37])
>>> cost
51325.0

我們需要命名切片 slice

slice 有三個(gè)屬性垛叨,start, stop, step伦糯。在創(chuàng)建構(gòu)造函數(shù)時(shí),可以適時(shí)忽略嗽元。

創(chuàng)建切片

>>> a=slice(10)   #stop為10, step默認(rèn)為1的分片
>>> a
slice(None, 10, None)
>>> a=slice(0, 10) # start為1敛纲, stop為10, step默認(rèn)為1的分片
>>> a
slice(0, 10, None)
>>> a=slice(0, 10, 2) # start為1, stop為10, step為2的分片
>>> a
slice(0, 10, 2)

示例:

>>> SHARES = slice(20, 23)
>>> PRICE = slice(31, 37)
>>> cost = int(record[SHARES]) * float(record[PRICE])
>>> cost
51325.0

這樣你避免了大量無法理解的硬編碼下標(biāo)剂癌,使得你的代碼更加清晰可讀了淤翔。

內(nèi)置的 slice() 函數(shù)創(chuàng)建了一個(gè)切片對象,可以被用在任何切片允許使用的地方佩谷。

>>> items = [0, 1, 2, 3, 4, 5, 6]
>>> a = slice(2, 4)
>>> items[a]
[2, 3]
>>> items[a] = [10,11]
>>> items[a]
[10, 11]
>>> items
[0, 1, 10, 11, 4, 5, 6]

如果你有一個(gè)切片對象 a旁壮,你可以分別調(diào)用它的 a.start , a.stop , a.step 屬性來獲取更多的信息。比如:

>>> a = slice(5, 50, 2)
>>> a.start
5
>>> a.stop
50
>>> a.step
2
>>>

我們也可以調(diào)用切片的 indices(size) 方法將它映射到一個(gè)確定大小的序列上琳要, 這個(gè)方法返回一個(gè)三元組 ( start, stop, step ) 寡具,所有值都會(huì)被合適的縮小以滿足邊界限制, 從而使用的時(shí)候避免出現(xiàn) IndexError 異常

>>> items = [0, 1, 2, 3, 4, 5, 6]
>>> a=slice(0,0)
>>> type(a)
<class 'slice'>
>>> b=a.indices(len(items))
>>> b
(0, 0, 1)
>>> type(b)
<class 'tuple'>

11. 序列中出現(xiàn)次數(shù)最多的元素

怎樣找出一個(gè)序列中出現(xiàn)次數(shù)最多的元素呢稚补?

我們可能需要collections.Counter 童叠, Counter 對象可以接受任意的由可哈希(hashable)元素構(gòu)成的序列對象。 在底層實(shí)現(xiàn)上课幕,一個(gè) Counter 對象就是一個(gè)字典厦坛,將元素映射到它出現(xiàn)的次數(shù)上。

from collections import Counter
>>> words = [
...     'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',
...     'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around', 'the',
...     'eyes', "don't", 'look', 'around', 'the', 'eyes', 'look', 'into',
...     'my', 'eyes', "you're", 'under'
... ]
>>> word_counts = Counter(words)
>>> 
>>> word_counts
Counter({'eyes': 8, 'the': 5, 'look': 4, 'into': 3, 'my': 3, 'around': 2, 'not': 1, "don't": 1, "you're": 1, 'under': 1})
>>> 
>>> type(word_counts)
<class 'collections.Counter'>
>>> 
>>> 
>>> dir(word_counts)
['__add__', '__and__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__le__', '__len__', '__lt__', '__missing__', '__module__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__weakref__', '_keep_positive', 'clear', 'copy', 'elements', 'fromkeys', 'get', 'items', 'keys', 'most_common', 'pop', 'popitem', 'setdefault', 'subtract', 'update', 'values']
>>> 
>>> word_counts['not']
1
>>> word_counts['eyes']
8
>>>

我們也可以手動(dòng)添加:

>>> morewords = ['why','are','you','not','looking','in','my','eyes']
>>> for word in morewords:
...     word_counts[word] += 1
... 
>>> word_counts['eyes']
>>> 9

只不過 Counter的內(nèi)部提供了 update的方法:

>>> word_counts.update(morewords)
>>> word_counts['eyes']
>>> 10

由于Counter實(shí)現(xiàn)了 hashable乍惊, 因此可以用于運(yùn)算操作杜秸。

>>> a = Counter(words)
>>> b = Counter(morewords)
>>> a
Counter({'eyes': 8, 'the': 5, 'look': 4, 'into': 3, 'my': 3, 'around': 2, 'not': 1, "don't": 1, "you're": 1, 'under': 1})
>>> b
Counter({'why': 1, 'are': 1, 'you': 1, 'not': 1, 'looking': 1, 'in': 1, 'my': 1, 'eyes': 1})
>>> 
>>> 
>>> a | b
Counter({'eyes': 8, 'the': 5, 'look': 4, 'into': 3, 'my': 3, 'around': 2, 'not': 1, "don't": 1, "you're": 1, 'under': 1, 'why': 1, 'are': 1, 'you': 1, 'looking': 1, 'in': 1})
>>> 
>>> a + b
Counter({'eyes': 9, 'the': 5, 'look': 4, 'my': 4, 'into': 3, 'not': 2, 'around': 2, "don't": 1, "you're": 1, 'under': 1, 'why': 1, 'are': 1, 'you': 1, 'looking': 1, 'in': 1})
>>> 
>>> 
>>> 
>>> a - b
Counter({'eyes': 7, 'the': 5, 'look': 4, 'into': 3, 'my': 2, 'around': 2, "don't": 1, "you're": 1, 'under': 1})
>>> 
>>> a & b
Counter({'my': 1, 'eyes': 1, 'not': 1})

因此,Counter這個(gè)特性會(huì)在很多場合使用润绎,比如合并統(tǒng)計(jì)數(shù)據(jù)撬碟,制表等等場合。

12. 通過某個(gè)關(guān)鍵字排序一個(gè)字典列表

你有一個(gè)字典列表莉撇,你想根據(jù)某個(gè)或某幾個(gè)字典字段來排序這個(gè)列表

使用 operator 模塊的 itemgetter 函數(shù)呢蛤。

>>> from operator import itemgetter
>>>  
>>> rows = [
...     {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
...     {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
...     {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
...     {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
... ]
>>> 
>>> 
>>> rows_by_fname = sorted(rows, key=itemgetter('fname'))
>>> rows_by_uid = sorted(rows, key=itemgetter('uid'))
>>> rows_by_all = sorted(rows, key=itemgetter('fname', 'uid'))
>>> 
>>> rows_by_fname
[{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}, {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}]
>>> 
>>> rows_by_uid
[{'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}]
>>> 
>>> rows_by_all
[{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}, {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}]

同樣,itemgetter() 有時(shí)候也可以用 lambda 表達(dá)式代替棍郎,但是沒有itemgetter() 效率高其障。比如:

>>> rows_by_fname = sorted(rows, key=lambda r: r['fname'])
>>> rows_by_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname']))
>>> 
>>> 
>>> 
>>> rows_by_lfname
[{'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}, {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}]
>>> rows_by_fname
[{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}, {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}]

最后,不要忘了這節(jié)中展示的技術(shù)也同樣適用于 min() 和 max() 等函數(shù)

>>> min(rows, key=itemgetter('uid'))
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001}
>>> max(rows, key=itemgetter('uid'))
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
>>> 

同樣需要注意的是涂佃,由于 dict 不是 hashable励翼。所以不能使用 min 蜈敢、maxsorted汽抚。但是tuple抓狭、sethasable,所以我們可以通過 lambdaitemgetter來完成對兩者的排序殊橙。

>>> rows = [
...     {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
...     {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
...     {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
...     {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
... ]
>>> 
>>> min(rows)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'dict' and 'dict'
>>> 
>>> max(rows)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'dict' and 'dict'
>>> 
>>> sorted(rows)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'dict' and 'dict'
>>> 
>>> min(rows, key=lambda r:(r['fname']))
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
>>> 
>>> max(rows, key=lambda r:(r['fname']))
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001}
>>> 
>>> sorted(rows, key=lambda r:(r['fname']))
[{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}, {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}]
>>> 

13. 排序不支持原生比較的對象

你想排序類型相同的對象辐宾,但是他們不支持原生的比較操作。

上一節(jié)我們知道sorted膨蛮、minmax季研、heapq.nsmallest敞葛、heapq.nlargest函數(shù)有一個(gè)關(guān)鍵字參數(shù) key,可以傳入一個(gè)callable 對象給它与涡。

這個(gè) callable 對象對每個(gè)傳入的對象返回一個(gè)值惹谐,這個(gè)值會(huì)被用來排序這些對象。而這個(gè)callable對象可以是我們使用lambda自定義對象驼卖,或者使用from operator import attrgetter或者from operator import itemgetter氨肌。

本章第3節(jié)、第4節(jié)酌畜、第7節(jié)怎囚、第12節(jié)都在講如何排序。

13.1 hashable 排序

當(dāng)裝有hashable類型的list桥胞、tuple恳守、set 我們可以使用任意的排序方式進(jìn)行排序。

list排序

>>> letters=['a', 'b', 'c', 'd', 'z', 'g']
>>> sorted(letters)
['a', 'b', 'c', 'd', 'g', 'z']
>>> 
>>> min(letters)
'a'
>>> max(letters)
'z'
>>> 
>>> import heapq
>>> 
>>> heapq.nsmallest(1, letters)
['a']
>>> heapq.nlargest(1, letters)
['z']
>>> sorted(letters)[0]
'a'
>>> sorted(letters)[len(letters) -1]
'z'

tuple排序

>>> letters=('a', 'b', 'c', 'd', 'z', 'g')
>>> sorted(letters)
['a', 'b', 'c', 'd', 'g', 'z']
>>> type(sorted(letters))
<class 'list'>
>>> min(letters)
'a'
>>> max(letters)
'z'
>>> import heapq
>>> 
>>> heapq.nsmallest(1, letters)
['a']
>>> heapq.nlargest(1, letters)
['z']
>>> sorted(letters)[0]
'a'
>>> sorted(letters)[len(letters) -1]
'z'

set排序

>>> letters=('a', 'b', 'c', 'd', 'z', 'g')
>>> letters=set(letters)
>>> sorted(letters)
['a', 'b', 'c', 'd', 'g', 'z']
>>> type(sorted(letters))
<class 'list'>
>>> min(letters)
'a'
>>> max(letters)
'z'
>>> import heapq
>>> 
>>> heapq.nsmallest(1,  letters)
['a']
>>> heapq.nlargest(1,  letters)
['z']
>>> sorted(letters)[0]
'a'
>>> sorted(letters)[len(letters) -1]
'z'

13.2 非hashable 排序

我們知道dict 贩虾、自定義對象是 非hashable的催烘。

裝有dict元素的列表

>>> import heapq
>>> portfolio = [
...     {'name': 'IBM', 'shares': 100, 'price': 91.1},
...     {'name': 'AAPL', 'shares': 50, 'price': 543.22},
...     {'name': 'FB', 'shares': 200, 'price': 21.09},
...     {'name': 'HPQ', 'shares': 35, 'price': 31.75},
...     {'name': 'YHOO', 'shares': 45, 'price': 16.35},
...     {'name': 'ACME', 'shares': 75, 'price': 115.65}
... ]
>>> heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
[{'name': 'YHOO', 'shares': 45, 'price': 16.35}, {'name': 'FB', 'shares': 200, 'price': 21.09}, {'name': 'HPQ', 'shares': 35, 'price': 31.75}]
>>> 
>>> heapq.nlargest(3, portfolio, key=lambda s: s['price'])
[{'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'ACME', 'shares': 75, 'price': 115.65}, {'name': 'IBM', 'shares': 100, 'price': 91.1}]
>>> 
>>> sorted(portfolio, key=lambda n: (n['name']))
[{'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'ACME', 'shares': 75, 'price': 115.65}, {'name': 'FB', 'shares': 200, 'price': 21.09}, {'name': 'HPQ', 'shares': 35, 'price': 31.75}, {'name': 'IBM', 'shares': 100, 'price': 91.1}, {'name': 'YHOO', 'shares': 45, 'price': 16.35}]
>>>
>>> sorted(portfolio, key=lambda n: (n['shares'], n['price']))
[{'name': 'HPQ', 'shares': 35, 'price': 31.75}, {'name': 'YHOO', 'shares': 45, 'price': 16.35}, {'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'ACME', 'shares': 75, 'price': 115.65}, {'name': 'IBM', 'shares': 100, 'price': 91.1}, {'name': 'FB', 'shares': 200, 'price': 21.09}]
>>> 
>>> min(portfolio, key=lambda n: (n['name']))
{'name': 'AAPL', 'shares': 50, 'price': 543.22}
>>> 
>>> max(portfolio, key=lambda n: (n['name']))
{'name': 'YHOO', 'shares': 45, 'price': 16.35}
>>>
 >>> from operator import itemgetter
>>>
>>> min(portfolio, key=itemgetter('name'))
{'name': 'AAPL', 'shares': 50, 'price': 543.22}
>>> 
>>> max(portfolio, key=itemgetter('name'))
{'name': 'YHOO', 'shares': 45, 'price': 16.35}
>>>  
>>> sorted(portfolio, key=itemgetter('name'))
[{'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'ACME', 'shares': 75, 'price': 115.65}, {'name': 'FB', 'shares': 200, 'price': 21.09}, {'name': 'HPQ', 'shares': 35, 'price': 31.75}, {'name': 'IBM', 'shares': 100, 'price': 91.1}, {'name': 'YHOO', 'shares': 45, 'price': 16.35}]

dict

>>> prices = {
...     'ACME': 45.23,
...     'AAPL': 612.78,
...     'IBM': 205.55,
...     'HPQ': 37.20,
...     'FB': 10.75
... }
>>> sorted(prices)
['AAPL', 'ACME', 'FB', 'HPQ', 'IBM']
>>> 
>>> min(prices)
'AAPL'
>>> 
>>> max(prices)
'IBM'
>>> sorted(prices, key=lambda n : prices[n])
['FB', 'HPQ', 'ACME', 'IBM', 'AAPL']
>>> 
>>> min(prices, key=lambda n : prices[n])
'FB'
>>> max(prices, key=lambda n : prices[n])
'AAPL'
>>> heapq.nsmallest(1, prices)
['AAPL']
>>> 
>>> heapq.nlargest(1, prices)
['IBM']
>>> 
>>> min(zip(prices.values(), prices.keys()))
(10.75, 'FB')
>>> 
>>> max(zip(prices.values(), prices.keys()))
(612.78, 'AAPL')
>>> sorted(zip(prices.values(), prices.keys()))
[(10.75, 'FB'), (37.2, 'HPQ'), (45.23, 'ACME'), (205.55, 'IBM'), (612.78, 'AAPL')]
>>> 
>>> min(prices.values())
10.75
>>> 
>>> max(prices.values())
612.78
>>> sorted(prices.values())
[10.75, 37.2, 45.23, 205.55, 612.78]

自定義對象

class User:
    def __init__(self, user_id):
        self.user_id = user_id

    def __repr__(self):
        return 'User({})'.format(self.user_id)
>>> users = [User(23), User(3), User(99)]
>>>
>>> sorted(users, key=lambda n: (n.user_id))
[User(3), User(23), User(99)]
>>> min(users, key=lambda n: (n.user_id))
User(3)
>>> max(users, key=lambda n: (n.user_id))
User(99)
>>>
>>> from operator import attrgetter
>>>
>>> sorted(users, key=attrgetter('user_id'))
[User(3), User(23), User(99)]
>>> min(users, key=attrgetter('user_id'))
User(3)
>>> max(users, key=attrgetter('user_id'))
User(99)

14. 通過某個(gè)字段將記錄分組

我們可以使用 itertools.groupby() 對 字典或者序列進(jìn)行分組。

groupby() 僅僅檢查連續(xù)的元素缎罢,如果事先并沒有排序完成的話伊群,分組函數(shù)將得不到想要的結(jié)果。

>>> rows = [
...     {'address': '5412 N CLARK', 'date': '07/01/2012'},
...     {'address': '5148 N CLARK', 'date': '07/04/2012'},
...     {'address': '5800 E 58TH', 'date': '07/02/2012'},
...     {'address': '2122 N CLARK', 'date': '07/03/2012'},
...     {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'},
...     {'address': '1060 W ADDISON', 'date': '07/02/2012'},
...     {'address': '4801 N BROADWAY', 'date': '07/01/2012'},
...     {'address': '1039 W GRANVILLE', 'date': '07/04/2012'},
... ]
>>> 
>>> # Sort by the desired field first
... rows.sort(key=itemgetter('date'))
>>> # Iterate in groups
... for date, items in groupby(rows, key=itemgetter('date')):
...     print(date)
...     for i in items:
...             print(' ', i)
>>>
07/01/2012
  {'address': '5412 N CLARK', 'date': '07/01/2012'}
  {'address': '4801 N BROADWAY', 'date': '07/01/2012'}
07/02/2012
  {'address': '5800 E 58TH', 'date': '07/02/2012'}
  {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}
  {'address': '1060 W ADDISON', 'date': '07/02/2012'}
07/03/2012
  {'address': '2122 N CLARK', 'date': '07/03/2012'}
07/04/2012
  {'address': '5148 N CLARK', 'date': '07/04/2012'}
  {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}

如果不想進(jìn)行排序策精,僅僅是想根據(jù)date對數(shù)據(jù)進(jìn)行分組舰始,且隨機(jī)訪問,那么歡迎使用defaultdict()

>>> from collections import defaultdict
>>> rows_by_date = defaultdict(list)
>>> for row in rows:
...     rows_by_date[row['date']].append(row)
>>>
>>> rows_by_date['07/04/2012']
[{'address': '5148 N CLARK', 'date': '07/04/2012'}, {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}]

15. 過濾序列元素

你有一個(gè)數(shù)據(jù)序列蛮寂,想利用一些規(guī)則從中提取出需要的值或者是縮短序列

使用列表推導(dǎo)

>>> mylist = [1, 4, -5, 10, -7, 2, 3, -1]
 >>> [n for n in mylist if n > 0]
[1, 4, 10, 2, 3]
>>>  t=[n for n in mylist if n < 0]
>>> 
>>> t
[-5, -7, -1]
>>> 
>>> type(t)
<class 'list'>

列表推導(dǎo)的一個(gè)潛在缺陷就是如果要過濾的列表過大產(chǎn)生一個(gè)非常大的結(jié)果集蔽午,占用大量內(nèi)存。所以建議使用生成器表達(dá)式迭代

生成器表達(dá)式迭代

>>> pos = (n for n in mylist if n > 0)
>>> 
>>> type(pos)
<class 'generator'>
>>> for x in pos:
...     print(x)
... 
1
4
10
2
3

如果過濾條件過于復(fù)雜酬蹋,那么可以把過濾條件放到一個(gè)函數(shù)中及老,并使用filter()

>>> values = ['1', '2', '-3', '-', '4', 'N/A', '5']
>>> def is_int(val):
...     try:
...             x = int(val)
...             return True
...     except ValueError:
...             return False
... 
>>> n=filter(is_int, values)
>>> type(n)
<class 'filter'>
>>> ivals = list(n)
>>> 
>>> ivals
['1', '2', '-3', '4', '5']

filter類是一個(gè)迭代器抽莱,因此如果我們需要變成一個(gè)列表時(shí)可以使用list()。如果我們需要遍歷時(shí)骄恶,請直接使用:

>>> n=filter(is_int, values)
>>> for x in n:
...     print(x)

過濾的同時(shí)修改數(shù)據(jù)

生成器表達(dá)式迭代和列表推導(dǎo)能夠干很多很多有意思的事情食铐,比如在過濾的同時(shí)完成對數(shù)據(jù)的進(jìn)一步改造:

mylist的中的數(shù)字全部平方,然后過濾丟棄僧鲁。

>>> mylist = [1, 4, -5, 10, -7, 2, 3, -1]
>>> import math
>>> [math.sqrt(n) for n in mylist if n > 0]
[1.0, 2.0, 3.1622776601683795, 1.4142135623730951, 1.7320508075688772]

將小于0的數(shù)用0代替虐呻,而不是丟棄掉。

>>> mylist = [1, 4, -5, 10, -7, 2, 3, -1]
>>>  [n if n > 0 else 0 for n in mylist]
[1, 4, 0, 10, 0, 2, 3, 0]

itertools.compress()

itertools.compress()以一個(gè) iterable 對象和一個(gè)相對應(yīng)的 Boolean 選擇器序列作為輸入?yún)?shù)寞秃。 然后輸出 iterable 對象中對應(yīng)選擇器為 True 的元素斟叼。

>>> addresses = [
...     '5412 N CLARK',
...     '5148 N CLARK',
...     '5800 E 58TH',
...     '2122 N CLARK',
...     '5645 N RAVENSWOOD',
...     '1060 W ADDISON',
...     '4801 N BROADWAY',
...     '1039 W GRANVILLE',
... ]
>>> counts = [ 0, 3, 10, 4, 1, 7, 6, 1]
>>> from itertools import compress
>>> more5 = [n > 5 for n in counts]  #`Boolean` 選擇器序列
>>> more5
[False, False, True, False, False, True, True, False]
>>> 
>>> compress=compress(addresses, more5)
>>> compress
<itertools.compress object at 0x1022b49b0>
>>> 
>>> list(compress)
['5800 E 58TH', '1060 W ADDISON', '4801 N BROADWAY']
>>> 

需要我們先創(chuàng)建Boolean 選擇器序列,然后才能使用春寿。

16. 從字典中提取子集

字典推導(dǎo)

字典推導(dǎo)能夠完成絕大多數(shù)的需求朗涩,并且速度更快。

>>> prices = {
...     'ACME': 45.23,
...     'AAPL': 612.78,
...     'IBM': 205.55,
...     'HPQ': 37.20,
...     'FB': 10.75
... }
... p1 = {key: value for key, value in prices.items() if value > 200}
... tech_names = {'AAPL', 'IBM', 'HPQ', 'MSFT'}
>>> p2 = {key: value for key, value in prices.items() if key in tech_names}
>>> p1
{'AAPL': 612.78, 'IBM': 205.55}
>>> 
>>> p2
{'AAPL': 612.78, 'IBM': 205.55, 'HPQ': 37.2}

dict() + 元組

>>> p1 = dict((key, value) for key, value in prices.items() if value > 200)
>>> 
>>> p1
{'AAPL': 612.78, 'IBM': 205.55}

17. 映射名稱到序列元素

當(dāng)我們從數(shù)據(jù)庫中讀出一行數(shù)據(jù)時(shí)绑改,返回的是一個(gè)元組谢床,我們需要通過下標(biāo)來查找我們想要的字段,這樣的代碼是不可讀的厘线。

collections.namedtuple()

collections.namedtuple()识腿,可以稱為命名元組, 可以通過一個(gè)存放對應(yīng)key的元組造壮,來解決映射的問題渡讼。

>>> from collections import namedtuple
>>> Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
>>> sub = Subscriber('jonesy@example.com', '2012-10-19')
>>> sub
Subscriber(addr='jonesy@example.com', joined='2012-10-19')
>>> 
>>> sub.addr
'jonesy@example.com'
>>> 
>>> sub.joined
'2012-10-19'
>>> type(sub)
<class '__main__.Subscriber'>

namedtuple 看起來想一個(gè)簡單對象,但是它卻支持所有的普通元組操作费薄。

>>> list(sub)
['jonesy@example.com', '2012-10-19']
>>> 
>>> len(sub)
2
>>> sub[1]
'2012-10-19'
>>> 
>>> addr, joined = sub
>>> addr
'jonesy@example.com'
>>> joined
'2012-10-19'

命名元組不可修改

>>> sub.addr='11@qq.com'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

如果非要進(jìn)行修改硝全,那么請使用 _replace() 方法, 但是它會(huì)創(chuàng)建一個(gè)全新的命名元組楞抡。

>>> newSub=sub._replace(addr='11@qq.com')
>>> newSub
Subscriber(addr='11@qq.com', joined='2012-10-19')

另外需要注意的是伟众,命名元組的另一個(gè)用途就是替代只讀字典的,因?yàn)樽值浯鎯?chǔ)需要更多的內(nèi)存空間召廷。 如果你需要構(gòu)建一個(gè)非常大的包含字典的數(shù)據(jù)結(jié)構(gòu)凳厢,那么使用命名元組會(huì)更加高效。

_replace()

_replace() 可以完成根據(jù)你的原始序列竞慢,來填充命名元組先紫。

>>> Stock = namedtuple('Stock', ['name', 'shares', 'price', 'date', 'time'])
>>> 
>>> stock_prototype = Stock('', 0, 0.0, None, None)
>>> 
>>> def dict_to_stock(s):
...     return stock_prototype._replace(**s)
>>> a = {'name': 'ACME',  'shares': 100,  'price': 123.45}
>>> dict_to_stock(a)
Stock(name='ACME', shares=100, price=123.45, date=None, time=None)

18. 轉(zhuǎn)換并同時(shí)計(jì)算數(shù)據(jù)

你需要在數(shù)據(jù)序列上執(zhí)行聚集函數(shù)(比如 sum() , min() , max() )之前,需要轉(zhuǎn)換或者過濾數(shù)據(jù)筹煮。

優(yōu)雅的辦法就是 生成器表達(dá)式遮精,也是我們必須第一個(gè)想到的。

>>> nums = [1, 2, 3, 4, 5]
>>> s = sum(x * x for x in nums)
>>> s
55
>>> s=sum(x for x in nums if x > 3)
>>> s
9
>>> import os
>>> files = os.listdir('/Users/faris/Desktop')
>>> if any(name.endswith('.py') for name in files):
...     print('There be python!')
... else:
...     print('Sorry, no python.')
There be python!

19. 合并多個(gè)字典或映射

如果我們有兩個(gè)字典ab本冲。我們需要查找一個(gè)值准脂,如果a中沒有,然后再去b中找檬洞。

collections. ChainMap 會(huì)將多個(gè)字典邏輯順序合并狸膏。

>>> a = {'x': 1, 'z': 3 }
>>> b = {'y': 2, 'z': 4 }
>>> 
>>> from collections import ChainMap
>>> c = ChainMap(a,b)
>>> print(c['x'])  
1
>>> print(c['y']) 
2
>>> print(c['z'])   打印的是a中的值,而不是b中的值
3

如果出現(xiàn)重復(fù)鍵添怔,那么第一次出現(xiàn)的映射值會(huì)被返回湾戳。 因此,例子程序中的 c['z'] 總是會(huì)返回字典 a 中對應(yīng)的值广料,而不是 b 中對應(yīng)的值砾脑。

>>> len(c)
3
>>> c.keys()
KeysView(ChainMap({'x': 1, 'z': 3}, {'y': 2, 'z': 4}))
>>> 
>>> c.values()
ValuesView(ChainMap({'x': 1, 'z': 3}, {'y': 2, 'z': 4}))
>>>  
>>> list(c.keys())
['z', 'x', 'y']
>>> 
>>> list(c.values())
[3, 1, 2]

對于字典的更新或刪除操作總是影響的是列表中第一個(gè)字典。

>>> c['z'] = 10
>>> c['w'] = 40
>>> del c['x']
>>> a
{'w': 40, 'z': 10}
>>> del c['y']
Traceback (most recent call last):
...
KeyError: "Key not found in the first mapping: 'y'"
>>>

如果你想物理合并艾杏,那么請使用dict.update()拦止,但是它會(huì)重新創(chuàng)建一個(gè)新的字典,并且對新字典的更新不會(huì)反應(yīng)在舊字典糜颠,對舊字典的更新也不會(huì)反應(yīng)在新字典上。

>>> a = {'x': 1, 'z': 3 }
>>> b = {'y': 2, 'z': 4 } 
>>> 
>>> merged = dict(b)
>>> 
>>> merged
{'y': 2, 'z': 4}
>>> merged.update(a)
>>> 
>>> merged
{'y': 2, 'z': 3, 'x': 1}
>>> 
>>> a
{'x': 1, 'z': 3}
>>> 
>>> b
{'y': 2, 'z': 4}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末萧求,一起剝皮案震驚了整個(gè)濱河市其兴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌夸政,老刑警劉巖元旬,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異守问,居然都是意外死亡匀归,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門耗帕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來穆端,“玉大人,你說我怎么就攤上這事仿便√鍐” “怎么了?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵嗽仪,是天一觀的道長荒勇。 經(jīng)常有香客問我,道長闻坚,這世上最難降的妖魔是什么沽翔? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮窿凤,結(jié)果婚禮上仅偎,老公的妹妹穿的比我還像新娘跨蟹。我一直安慰自己,他們只是感情好哨颂,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布喷市。 她就那樣靜靜地躺著,像睡著了一般威恼。 火紅的嫁衣襯著肌膚如雪品姓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天箫措,我揣著相機(jī)與錄音腹备,去河邊找鬼。 笑死斤蔓,一個(gè)胖子當(dāng)著我的面吹牛植酥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弦牡,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼友驮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了驾锰?” 一聲冷哼從身側(cè)響起卸留,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎椭豫,沒想到半個(gè)月后耻瑟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赏酥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年喳整,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裸扶。...
    茶點(diǎn)故事閱讀 38,814評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡框都,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出姓言,到底是詐尸還是另有隱情瞬项,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布何荚,位于F島的核電站囱淋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏餐塘。R本人自食惡果不足惜妥衣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧税手,春花似錦蜂筹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至兵扬,卻和暖如春麻裳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背器钟。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工津坑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人傲霸。 一個(gè)月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓疆瑰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親昙啄。 傳聞我的和親對象是個(gè)殘疾皇子穆役,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評論 2 351

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