חדש בפייתון מילון קפוא
פייתון 15 הוסיפה מנגנון חדש שפותר כאב ראש מאוד ישן. זה נקרא frozendict וזה פשוט dict שאי אפשר לשנות אותו. עכשיו אני מבין שאתם מופתעים, מי צריך מילון שאי אפשר לשנות את מה שכתוב בו? מה לא מספיק לך dataclasses? נכון dataclass לא קפוא בברירת מחדל אבל אפשר בקלות להעביר frozen=True בבנאי ולקבל אותו קפוא.
התשובה היא שתמיד טוב שיש דברים שלא משתנים ולא תמיד צריך או רצוי להגדיר dataclass. לפעמים יש לי מידע שקיבלתי דרך API או מידע שאני לא בטוח מה המבנה שלו, ובכל זאת אני רוצה להקפיא אותו.
בשביל ליצור מילון קפוא מספיק להשתמש במילה החדשה frozendict החל מפייתון 3.15:
frozendict({"a": 10 })
או אם יש לכם מילון ביד אפשר לעטוף אותו ב frozendict:
d = {"a": 10}
f = frozendict(d)
והחלק הכי טוב במילון הקפוא הוא שיש לו hash ולכן אפשר להשתמש בו בתור ערך במילון. בדוגמה הבאה אני מפעיל lru_cache על פונקציה שמקבלת מילון וסוכמת ברקורסיה את כל הערכים המספריים באותו מילון. עד פייתון 3.15 זה לא היה עובד כי lru_cache דורשת שנשמור את הפרמטרים במילון המטמון. עכשיו עם frozendict הערך נשמר במילון ואנחנו מקבלים מטמון במתנה:
from functools import lru_cache
@lru_cache
def sum_values(d):
numbers = sum(v for v in d.values() if type(v) == int)
others = {k: v for k, v in d.items() if not isinstance(v, int)}
if len(others) == 0:
return numbers
return numbers + sum_values(frozendict({ k: sum_values(v) for k, v in others.items() }))
print(sum_values(frozendict(
{
"a": 10,
"b": 20,
"c": frozendict({ "a": 30, "b": 40 }),
"d": frozendict({ "e": frozendict({"f": 100}) })
})))