Python中使用字典的幾個小技巧

小小後端發表於2018-09-18

1 解包

所謂解包,就是將字典通過 ** 操作符轉為 Key=Value 的形式,這種形式可以直接傳給函式作為關鍵字引數。 說說適用的幾種情況。

1.1 搜尋拼接條件

當應用中使用類似 SQLAlchemy 的 ORM 形式讀取資料的時候,不同搜尋條件,傳入給 ORM 的搜尋引數也隨之改變。 下面是圖書表的部分資料(只展示了部分欄位)

+----+---------------+-------------------------+-------+
| id | category_name | book_name               | price |
+----+---------------+-------------------------+-------+
|  1 | 人文社科      | 人類簡史                | 42.90 |
|  2 | 人文社科      | 世界簡史                | 25.50 |
|  3 | 經濟管理      | 極致產品                | 37.00 |
|  4 | 經濟管理      | 史蒂夫·賈伯斯傳         | 44.20 |
|  5 | 經濟管理      | 影響力                  | 41.20 |
+----+---------------+-------------------------+-------+
複製程式碼

搜尋時,我們會以這樣的形式執行查詢方法

books = Book.query.filter_by(id=1, book_name='影響力').all()
複製程式碼

但是由於傳入引數會根據搜尋條件的變化而變化,無法直接寫出有哪些引數,這個時候就可以使用字典解包

condition = {}
if book_id:
	condition['id'] = id
if book_name:
	condition['name'] = book_name
books = Book.query.filter_by(**condition).all()
複製程式碼

這樣就 OK 了

1.2 方法引數太多,為程式碼美觀使用

new_book = Book(category_name='文學小說', book_name='解憂雜貨店', price=28.8,
				...)
db.session.add(new_book)
複製程式碼

改成這樣的話,美觀一些

book_param = {'category_name': '文學小說', 'book_name': '解憂雜貨店', 'price': 28.8,
			  ...}
new_book = Book(**book_param)
db.session.add(new_book)
複製程式碼

並且,在上述新增圖書過程中,都會對提交的引數進行校驗,而校驗方法返回的結果(也就是 book_param 和其它資訊)一般也都是字典,所以使用字典解包的方式更符合實際場景。

總之,適當使用字典解包對方法進行傳參,可以讓我們的程式碼更靈活。

2 setdefault() 的使用

先看下這個方法怎麼使用

dict.setdefault(key, default=None)

如果字典中包含有給定鍵,則返回該鍵對應的值,否則返回為該鍵設定的值。

很多時候我們需要對列表根據元素的某個 key 轉化成一個包含列表的字典。比如,上面的資料中,我希望得到一個字典,字典的 key 是圖書分類,value 是屬於該分類的圖書列表。我們通常會這樣寫

books_dict = {}
for book in book_list:
    if book['category_name'] not in books_dict.keys():
        books_dict[book['category_name']] = []
    books_dict[book['category_name']].append(book)
複製程式碼

當然,這樣寫是正確的,能得到預期結果

{
	"人文社科": [{
		"id": 1,
		"category_name": "人文社科",
		"book_name": "人類簡史",
		"price": 42.9
	}, {
		"id": 2,
		"category_name": "人文社科",
		"book_name": "世界簡史",
		"price": 25.5
	}],
	"經濟管理": [{
		"id": 3,
		"category_name": "經濟管理",
		"book_name": "極致產品",
		"price": 37.0
	}, {
		"id": 4,
		"category_name": "經濟管理",
		"book_name": "史蒂夫·賈伯斯傳",
		"price": 44.2
	}, {
		"id": 5,
		"category_name": "經濟管理",
		"book_name": "影響力",
		"price": 41.2
	}]
}
複製程式碼

但是如果使用字典的 setdefault() 方法話,可以少寫幾行程式碼,看起來也優雅一些

books_dict = {}
for book in book_list:
    books_dict.setdefault(book['category_name'], []).append(book)
複製程式碼

3 字典合併

常用的合併方式

# new_dict = {**dict1, **dict2, ...}
# 合併多個字典,如果字典中存在相同的 key 的話,後面的會覆蓋掉前面的
# 比如 dict2 會覆蓋 dict1 中的 key 相同的值

>>> a = {'name': 'x', 'age': 13}
>>> b = {'name': 'y'}
>>> c = {**a, **b}
>>> c
{'name': 'y', 'age': 13}

# dict1.update(dict2)
# 合併兩個字典,如果字典中存在相同的 key 的話,dict2 會覆蓋 dict1 的對應值
# 理解為更新某個字典應該更合適

>>> a.update(b)
>>> a
{'name': 'y', 'age': 13}
複製程式碼

有時我們碰到合併字典的情況也不少。比如,我們準備根據一本書的基本資訊建立一本新書

# to_dict 將 ORM 物件轉為字典,是自定義的,理解意思就好
base_book = Book.query.filter_by(id=1).first().to_dict()
# 提交的引數需要校驗,校驗成功後返回值包含 book_param ,內容和下面類似
book_param = {'book_name': '國家寶藏', 'price': 55.60}
# 同時需要更新新書的建立時間和更新時間
time_param = {'created_at': current_time, 'updated_at': current_time}
# 新增書籍
new_book = Book(**{**base_book, **book_param, **time_param})
db.session.add(new_book)
複製程式碼

當然,如果只是合併兩個字典的話,也可以使用 update() 方法。

假設我們只需要合併 base_bookbook_param

base_book.update(book_param)
複製程式碼

這也可以工作,不過要注意,這樣會修改 base_book 中的值。

如果只是單純的更新某個字典的資訊的話,update() 方法顯然最合適。對於當前需求的話,還是第一種方式更合適。

本文首發於公眾號「小小後端」,關注並回復關鍵字「1024」,各種 IT 學習資料大禮包免費贈送。

相關文章