[python] defaultdic, __call__

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"

在〈[python] defaultdic, __call__〉中有 1 則留言

發佈留言

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料