Dict ו-File ב-Python

Dict Hash Table

המבנה של טבלת גיבוב (hash) יעיל/ערך ב-Python נקרא 'dict'. תוכן של מילון יכול להיכתב כסדרה של צמדי מפתח/ערך בתוך סוגריים מסולסלים { }, למשל dict = {key1:value1, key2:value2, ... }. "מילון ריק" הוא פשוט זוג ריק של סוגריים מסולסלים {}.

כדי לחפש או להגדיר ערך במילון משתמשים בסוגריים מרובעים, למשל: dict['foo'] מחפש את הערך במפתח 'foo'. מחרוזות, מספרים וקבוצות של ערכים (tuples) משמשים כמפתחות, וכל סוג יכול לשמש כערך. סוגים אחרים עשויים לפעול בצורה לא תקינה כמפתחות (מחרוזות וצמודים פועלים בצורה נקייה כי הם לא ניתנים לשינוי). חיפוש ערך שלא נמצא במילון יגרום להודעת השגיאה KeyError. אפשר להשתמש ב-"in" כדי לבדוק אם המפתח נמצא במילון, או להשתמש ב-dict.get(key) שמחזיר את הערך או None אם המפתח לא נמצא (או ב-get(key, not-found) שמאפשר לציין איזה ערך להחזיר במקרה שלא נמצא).

  ## Can build up a dict by starting with the empty dict {}
  ## and storing key/value pairs into the dict like this:
  ## dict[key] = value-for-that-key
  dict = {}
  dict['a'] = 'alpha'
  dict['g'] = 'gamma'
  dict['o'] = 'omega'

  print(dict) ## {'a': 'alpha', 'o': 'omega', 'g': 'gamma'}

  print(dict['a'])     ## Simple lookup, returns 'alpha'
  dict['a'] = 6       ## Put new key/value into dict
  'a' in dict         ## True
  ## print(dict['z'])                  ## Throws KeyError
  if 'z' in dict: print(dict['z'])     ## Avoid KeyError
  print(dict.get('z'))  ## None (instead of KeyError)

dict עם המפתחות 'a' 'o' 'g'

כברירת מחדל, לולאת for במילון מבצעת איטרציה על המפתחות שלו. המפתחות יופיעו בסדר שרירותי. השיטות dict.keys() ו-dict.values() מחזירות רשימות של המפתחות או הערכים באופן מפורש. יש גם את ה-items() שמחזיר רשימה של צמדי (key, value), והיא הדרך היעילה ביותר לבדוק את כל נתוני הערכים של המפתחות במילון. אפשר להעביר את כל הרשימות האלה לפונקציה sorted().

  ## By default, iterating over a dict iterates over its keys.
  ## Note that the keys are in a random order.
  for key in dict:
    print(key)
  ## prints a g o

  ## Exactly the same as above
  for key in dict.keys():
    print(key)

  ## Get the .keys() list:
  print(dict.keys())  ## dict_keys(['a', 'o', 'g'])

  ## Likewise, there's a .values() list of values
  print(dict.values())  ## dict_values(['alpha', 'omega', 'gamma'])

  ## Common case -- loop over the keys in sorted order,
  ## accessing each key/value
  for key in sorted(dict.keys()):
    print(key, dict[key])

  ## .items() is the dict expressed as (key, value) tuples
  print(dict.items())  ##  dict_items([('a', 'alpha'), ('o', 'omega'), ('g', 'gamma')])

  ## This loop syntax accesses the whole dict by looping
  ## over the .items() tuple list, accessing one (key, value)
  ## pair on each iteration.
  for k, v in dict.items(): print(k, '>', v)
  ## a > alpha    o > omega     g > gamma

הערה לגבי אסטרטגיה: מבחינת ביצועים, המילון הוא אחד הכלים החשובים ביותר, ורצוי להשתמש בו בכל מקום שבו אפשר כדרך קלה לארגון נתונים. לדוגמה, אתם יכולים לקרוא קובץ יומן שבו כל שורה מתחילה בכתובת IP, ולאחסן את הנתונים לצו לפי כתובת ה-IP כמפתח ואת רשימת השורות שבהן הם מופיעים כערך. אחרי שקוראים את כל הקובץ, אפשר לחפש כל כתובת IP ולראות באופן מיידי את רשימת השורות שלה. המילון לוקח נתונים מפוזרים והופך אותם לנתונים עקביים.

עיצוב הכתבה

אפשר להשתמש באופרטור % כדי להחליף ערכים ממילון במחרוזת לפי שם:

  h = {}
  h['word'] = 'garfield'
  h['count'] = 42
  s = 'I want %(count)d copies of %(word)s' % h  # %d for int, %s for string
  # 'I want 42 copies of garfield'

  # You can also use str.format().
  s = 'I want {count:d} copies of {word}'.format(h)

Del

האופרטור del מבצע מחיקה. במקרה הפשוט ביותר, היא יכולה להסיר את ההגדרה של משתנה, כאילו המשתנה הזה לא הוגדר. ניתן להשתמש ב-Dell גם ברכיבי רשימה או בפרוסות כדי למחוק חלק זה ברשימה ולמחוק ערכים ממילון.

  var = 6
  del var  # var no more!

  list = ['a', 'b', 'c', 'd']
  del list[0]     ## Delete first element
  del list[-2:]   ## Delete last two elements
  print(list)      ## ['b']

  dict = {'a':1, 'b':2, 'c':3}
  del dict['b']   ## Delete 'b' entry
  print(dict)      ## {'a':1, 'c':3}

קבצים

הפונקציה open() פותחת ומחזירה מאגר קובץ שאפשר להשתמש בו כדי לקרוא או לכתוב קובץ בדרך הרגילה. הקוד f = open('name', 'r') פותח את הקובץ במשתנה f, מוכן לפעולות קריאה, ומשתמשים ב-f.close() בסיום. במקום 'r', משתמשים ב-'w' לכתיבה וב-'a' להוספה. לולאת for הרגילה פועלת בקבצי טקסט, ומבצעת איטרציה על השורות בקובץ (היא פועלת רק בקבצי טקסט, ולא בקבצים בינאריים). טכניקת לולאת for היא דרך פשוטה ויעילה לבדוק את כל השורות בקובץ טקסט:

  # Echo the contents of a text file
  f = open('foo.txt', 'rt', encoding='utf-8')
  for line in f:   ## iterates over the lines of the file
    print(line, end='')    ## end='' so print does not add an end-of-line char
                           ## since 'line' already includes the end-of-line.
  f.close()

היתרון של קריאת שורה אחת בכל פעם הוא שלא כל הקובץ צריך להיכנס לזיכרון בבת אחת. זה שימושי אם רוצים לבדוק כל שורה בקובץ של 10GB בלי להשתמש ב-10GB של זיכרון. ה-method f.readlines() קורא את כל הקובץ לזיכרון ומחזיר את התוכן שלו כרשימה של השורות שלו. שיטת f.read()‎ קוראת את כל הקובץ למחרוזת אחת. זוהי דרך נוחה לטפל בטקסט בבת אחת, למשל באמצעות ביטויים רגולריים שנראה בהמשך.

לכתיבה, השיטה f.write(string) היא הדרך הקלה ביותר לכתוב נתונים בקובץ פלט פתוח. לחלופין, אפשר להשתמש ב-"print" עם קובץ פתוח, כמו "print(string, file=f)".

קבצים בפורמט Unicode

כדי לקרוא ולכתוב קבצים בקידוד Unicode, משתמשים במצב 't' ומציינים באופן מפורש את הקידוד:


with open('foo.txt', 'rt', encoding='utf-8') as f:
  for line in f:
    # here line is a *unicode* string

with open('write_test', encoding='utf-8', mode='wt') as f:
    f.write('\u20ACunicode\u20AC\n') #  €unicode€
    # AKA print('\u20ACunicode\u20AC', file=f)  ## which auto-adds end='\n'

התפתחות מצטברת של פעילות גופנית

כשמפתחים תוכנית ב-Python, לא כותבים את הכול בשלב אחד. במקום זאת, ציינו רק ציון דרך ראשון, למשל: "השלב הראשון הוא חילוץ רשימת המילים". כותבים את הקוד כדי להגיע לנקודת הציון הזו, ומדפיסים את מבני הנתונים בנקודה הזו. לאחר מכן אפשר להריץ את sys.exit(0) כדי שהתוכנית לא תרוץ קדימה לחלקים שעדיין לא הושלמו. אחרי שקוד אבן הדרך פועל, אפשר לעבוד על הקוד של אבן הדרך הבאה. כשאתם יכולים להדפיס את המשתנים במצב מסוים, אתם יכולים להבין איך צריך לבצע את הטרנספורמציה של המשתנים האלה כדי להגיע למצב הבא. Python מהיר מאוד עם הדפוס הזה, מה שמאפשר לכם לבצע שינוי קטן ולהריץ את התוכנה כדי לראות איך היא פועלת. כדאי לנצל את זמני הטיפול המהירים כדי לפתח את התוכנית שלכם בהדרגה.

תרגול: wordcount.py

שילוב של כל החומר הבסיסי ב-Python – מחרוזות, רשימות, מילואים, צמדי מחרוזות, קבצים – כדאי לנסות את התרגיל wordcount.py בסיכום Basic Exercises.