字典對象的 Pythonic 用法(上篇)
點擊
上方藍字
,快速關注我們)
編譯:伯樂在線 - 劉志軍
foofish.net/python-dict-usage.html
如有好文章投稿,請點擊 → 這裡了解詳情
字典對象在Python中作為最常用的數據結構之一,和數字、字元串、列表、元組並列為5大基本數據結構,字典中的元素通過鍵來存取,而非像列表一樣通過偏移存取。筆者總結了字典的一些常用Pyhonic用法,這是字典的Pythonic用法的上篇
0. 使用 in/not in 檢查 key 是否存在於字典
判斷某個 key 是否存在於字典中時,一般初學者想到的方法是,先以列表的形式把字典所有鍵返回,再判斷該key是否存在於鍵列表中:
dictionary
=
{}
keys
=
dictionary
.
keys
()
for
k
in
keys
:
if
key
==
k
:
True
break
更具Pythonic的用法是使用in關鍵字來判斷 key 是否 存在於字典中:
if
key
in
dictionary
:
True
else
:
False
1. 使用 setdefault() 初始化字典鍵值
使用字典的時候經常會遇到這樣一種應用場景:動態更新字典,像如下代碼,如果 key 不在 dictionary 中那麼就添加它並把它對應的值初始為空列表 [] ,然後把元素 append 到空列表中:
dictionary
=
{}
if
"key"
not
in
dictionary
:
dictionary
[
"key"
]
=
[]
dictionary
[
"key"
].
append
(
"list_item"
)
儘管這段代碼沒有任何邏輯錯誤,但是我們可以使用setdefault來實現更Pyhonic的寫法:
dictionary
=
{}
dictionary
.
setdefault
(
"key"
,
[]).
append
(
"list_item"
)
字典調用 setdefault 方法時,首先檢查 key 是否存在,如果存在該方法什麼也不做,如果不存在 setdefault 就會創建該 key,並把第二個參數[]作為 key 對應的值。
2. 使用 defaultdict() 初始化字典
初始化一個字典時,如果初始情況下希望所有 key 對應的值都是某個默認的初始值,比如有一批用戶的信用積分都初始為100,現在想給 a 用戶增加10分
d
=
{}
if
"a"
not
in
d
:
d
[
"a"
]
=
100
d
[
"a"
]
+=
10
同樣這段代碼也沒任何問題,換成更pyhtonic的寫法是:
from
collections
import
defaultdict
d
=
defaultdict
(
lambda
:
100
)
d
[
"a"
]
+=
10
defaultdict 是位於 collections 模塊下,它是 dict 類的子類,語法結構是:
class collections.defaultdict([default_factory[, ...]])
第一個參數default_factory是一個工廠方法,每次初始化某個鍵的時候將會被調用,value就是default_factory返回的值,剩下的參數和dict()函數接收的參數一樣
3. 使用 iteritems() 迭代大數據
迭代大數據字典時,如果是使用 items() 方法,那麼在迭代之前,迭代器迭代前需要把數據完整地載入到內存,這種方式不僅處理非常慢而且浪費內存,下面代碼約佔1.6G內存(為什麼是1.6G?可以參考:
http://stackoverflow.com/questions/4279358/pythons-underlying-hash-data-structure-for-dictionaries)
d
=
{
i
:
i
*
2
for
i
in
xrange
(
10000000
)}
for
key
,
value
in
d
.
items
()
:
(
"{0} = {1}"
.
format
(
key
,
value
))
而使用 iteritem() 方法替換 items() ,最終實現的效果一樣,但是消耗的內存降低50%,為什麼差距那麼大呢?因為 items() 返回的是一個 list,list 在迭代的時候會預先把所有的元素載入到內存,而 iteritem() 返回的一個迭代器(iterators),迭代器在迭代的時候,迭代元素逐個的生成。
d
=
{
i
:
i
*
2
for
i
in
xrange
(
10000000
)}
for
key
,
value
in
d
.
iteritem
()
:
(
"{0} = {1}"
.
format
(
key
,
value
))
4. 高效合并字典
普通方法
合并多個字典的時候可以用一行代碼實現:
x
=
{
"a"
:
1
,
"b"
:
2
}
y
=
{
"b"
:
3
,
"c"
:
4
}
z
=
dict
(
x
.
items
()
+
y
.
items
())
這種寫法看起來很Pythonic,但仔細分析的話,它的執行效率並不高,items()方法在python2.7中返回的是列表對象,兩個列表相加得到一個新的列表,這樣內存中存在3個列表對象,如果兩個列表的大小都是1G,那麼執行這段代碼需要佔用4G的空間來創建這個字典。此外這段代碼在Python3中會報錯,因為python3中items()返回的是dict_items對象,而不是列表。
>>>
c
=
dict
(
a
.
items
()
+
b
.
items
())
Traceback
(
most recent call
last
)
:
File
"
,
line
1
,
in
<
module
>
TypeError
:
unsupported operand type
(
s
)
for
+:
"dict_items"
and
"dict_items"
在python3中,你需要明確地強制轉換成list對象:
z = dict(list(x.items()) + list(y.items()))
Pythonic方法
在Python3.5中提供了一種全新的Pythonic方法:
z = {**x, **y}
不過考慮到大部分系統還是基於Python2,所以一種更兼容的pythonic方法是:
z
=
x
.
copy
()
z
.
update
(
y
)
當然,你可以把它封裝成一個函數:
def
merge_dicts
(
*
dict_args
)
:
"""
可以接收1個或多個字典參數
"""
result
=
{}
for
dictionary
in
dict_args
:
result
.
update
(
dictionary
)
return
result
z
=
merge_dicts
(
a
,
b
,
c
,
d
,
e
,
f
,
g
)
其他方法
還有其他方式來合并字典,但是性能不一定是最優的,比如: python2.7可以支持字典推導式
{k: v for d in dicts for k, v in d.items()}
python2.6及以下版本使用
{k: v for d in dicts for k, v in d.items()}
性能對比
import
timeit
>>>
min
(
timeit
.
repeat
(
lambda
:
{
**
x
,
**
y
}))
# python3.5
0.4094954460160807
>>>
min
(
timeit
.
repeat
(
lambda
:
merge_two_dicts
(
x
,
y
)))
0.5726828575134277
>>>
min
(
timeit
.
repeat
(
lambda
:
{
k
:
v
for
d
in
(
x
,
y
)
for
k
,
v
in
d
.
items
()}
))
1.163769006729126
>>>
min
(
timeit
.
repeat
(
lambda
:
dict
((
k
,
v
)
for
d
in
(
x
,
y
)
for
k
,
v
in
d
.
items
())))
2.2345519065856934
直接使用python3.5中的{**x, **y}是最快的,使用update次之,用字典推導式相對來說是最慢的。
看完本文有收穫?請轉
發分享給更多人
關注「P
ython開發者」,提升Python技能
![](https://pic.pimg.tw/zzuyanan/1488615166-1259157397.png)
![](https://pic.pimg.tw/zzuyanan/1482887990-2595557020.jpg)
※Python編寫知乎爬蟲實踐
※基於 Python 和 Scikit-Learn 的機器學習介紹
※Fedora寫給Python的情書
※字典對象的 Pythonic 用法
※Python將是人工智慧時代的最佳編程語言
TAG:Python |
※讀懂Python的Mock對象庫(2)
※讀懂Python的Mock對象庫(1)
※簡單定義Python和Scala的類和對象
※Web Pages WebSecurity 對象
※POJO 對象setter 方法是否合適return 「this」
※XML DOM-ProcessingInstruction 對象
※使用Tensorflow Object Detection API實現對象檢測
※code值獲取內部枚舉類對象(自定義EnumUtil PackageUtil工具類)
※ASP FileSystemObject 對象
※Supreme 的下一個奢華品牌合作對象是 Dolce&Gabanna?
※Kotlin 類和對象
※Web Pages Database 對象
※ASP Application 對象
※XML DOM-DocumentImplementation 對象
※A$AP Rocky 新專輯曲目曝光?合作對象包含 Snoop Dogg、Kid Cudi、T.I. 等人
※ASP.NET Web Forms ArrayList 對象
※django框架:HttpResponse對象
※不打開文件獲取名稱。Excel VBA Application對象GetOpenFilename方法教程
※ASP Response 對象
※ES6 Promise 對象