case1:
有時候我們會希望在dictionary中遞增value
但往往需要重複檢查key值是否存在並設定value為empty list, empty set或為0
這種情況使用setdefault或是sefaultdict就是一個好選擇
case2:
有時我們會希望function在執行時同時記錄一些狀態值
使用__call__來建立一個可以呼叫的物件
class_info = {
'math': ['amy', 'david'],
'history': ['amy'],
'biology': ['david', 'john']
}
student_info = {}
for class_name in class_info:
for student in class_info[class_name]:
if student not in student_info:
#先檢查student是否存在
#不存在就先設定為空的list
student_info[student] = []
student_info[student].append(class_name)
print(student_info)
#{'john': ['biology'], 'david': ['biology', 'math'], 'amy': ['math', 'history']}
student_info = {}
for class_name in class_info:
for student in class_info[class_name]:
#setdefault會先檢查student是否存在 若不存在設定成空的list
student_info.setdefault(student, []).append(class_name)
print(student_info)
#{'john': ['biology'], 'david': ['biology', 'math'], 'amy': ['math', 'history']}
import collections
#defaultdict接受一個factory method作為參數
student_info = collections.defaultdict(list)
for class_name in class_info:
for student in class_info[class_name]:
student_info[student].append(class_name)
print(student_info)
#defaultdict(<class 'list'>, {'john': ['biology'], 'david': ['biology', 'math'], 'amy': ['math', 'history']})
class CountMissing(object):
def __init__(self):
self.added = 0
def __call__(self):
self.added += 1
return []
#只要有__call__就可以當成function來呼叫
counter = CountMissing()
counter()
assert callable(counter)
assert counter.added == 1
student_counter = CountMissing()
#defaultdic的第二個參數會作為defaultdict初始的內容
student_info = collections.defaultdict(student_counter, {'john': ['math']})
print(student_info)
#defaultdict(<__main__.CountMissing object at 0x036EC8F0>, {'john': ['math']})
for class_name in class_info:
for student in class_info[class_name]:
#student_counter回傳空的list給defaultdict當作預設值 同時會記錄student的數量
student_info[student].append(class_name)
assert student_counter.added == 2
print(student_info)
#defaultdict(<__main__.CountMissing object at 0x036EC8F0>, {'john': ['math', 'biology'], 'amy': ['math', 'history'], 'david': ['math', 'biology']})
#adapt from "effective python, ch3"
Nice tips!