תוכניות שירות ב-Python

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

מערכת קבצים – os, os.path, Shutil

המודולים *os* ו-*os.path* כוללים פונקציות רבות לאינטראקציה עם מערכת הקבצים. המודול *shutil* יכול להעתיק קבצים.

  • מסמכי מודול של OS
  • filenames = os.listdir(dir) -- רשימה של שמות קבצים בנתיב ספרייה זה (לא כולל . ו-..). שמות הקבצים הם רק השמות בספרייה, לא הנתיבים המוחלטים שלהם.
  • os.path.join(dir, filename) – ניתן להשתמש בשם קובץ מהרשימה שלמעלה כדי להרכיב יחד את שם הקובץ וה-dir כדי ליצור נתיב
  • os.path.bpath(path) -- נתיב, החזרת טופס מוחלט לדוגמה /home/nick/foo/bar.html
  • os.path.dirname(path), os.path.basename(path) -- מזינים את dir/foo/bar.html, מחזיר את שם האתר "dir/foo" ואת שם הבסיס "bar.html"
  • os.path.exists(path) – אם הוא קיים
  • os.mkdir(dir_path) – יוצר dir אחד, os.makedirs(dir_path) יוצר את כל ה-dirs הדרושים בנתיב הזה
  • segmentil.copy(source-path, dest-path) – העתקת קובץ (צריכות להיות ספריות של נתיב יעד)
## Example pulls filenames from a dir, prints their relative and absolute paths
def printdir(dir):
  filenames = os.listdir(dir)
  for filename in filenames:
    print(filename)  ## foo.txt
    print(os.path.join(dir, filename)) ## dir/foo.txt (relative to current dir)
    print(os.path.abspath(os.path.join(dir, filename))) ## /home/nick/dir/foo.txt

גילוי המודול עובד היטב עם הפונקציות המובנות של python help() ו-dir() . במפענח, מבצעים ייבוא של os, ואז משתמשים בפקודות האלה כדי לבדוק מה זמין במודול: dir(os), help(os.listdir), dir(os.path), help(os.path.dirname).

הפעלת תהליכים חיצוניים – תהליך משנה

מודול *תהליך המשנה* הוא דרך פשוטה להריץ פקודה חיצונית ולתעד את הפלט שלה.

  • מסמכי מודולים של תהליכי משנה
  • פלט = submenu.check_output(cmd, stderr=sub תמצא.STDOUT) -- מפעיל את הפקודה, ממתין ליציאה ומחזיר את טקסט הפלט. הפקודה רצה עם הפלט הסטנדרטי והשגיאה הרגילה שלה שמשולבות בטקסט פלט אחד. אם לא תצליח, תופיע הודעת השגיאה CalledProcessError.
  • כדי לקבל שליטה רבה יותר על ההפעלה של תהליך המשנה, כדאי לעיין ב-subcess.popen class
  • יש גם subcess.call(cmd) פשוטה שמריצה את הפקודה, מעבירה את הפלט לפלט ומחזירה את קוד השגיאה. אפשר לעשות את זה אם רוצים להריץ את הפקודה אבל לא צריך לתעד את הפלט במבני הנתונים של python.
import subprocess

## Given a dir path, run an external 'ls -l' on it --
## shows how to call an external program
def listdir(dir):
  cmd = 'ls -l ' + dir
  print("Command to run:", cmd)   ## good to debug cmd before actually running it
  (status, output) = subprocess.getstatusoutput(cmd)
  if status:    ## Error case, print the command's output to stderr and exit
    sys.stderr.write(output)
    sys.exit(status)
  print(output)  ## Otherwise do something with the command's output

חריגים

חריגה מייצגת שגיאה של זמן ריצה אשר עוצרת את הביצוע הרגיל בשורה מסוימת ומעבירה את הבקרה לקוד טיפול בשגיאות. סעיף זה מציג את השימושים הבסיסיים ביותר של חריגים. לדוגמה, שגיאת זמן ריצה יכולה להיות שלמשתנה מסוים בתוכנית אין ערך (ValueError .. סביר להניח שראית שגיאה כזו מספר פעמים), או ששגיאה של פעולה פתוחה עקב קובץ לא קיים (IOError). מידע נוסף זמין במדריך בנושא חריגים ורשימת החריגים המלאה.

ללא קוד טיפול בשגיאות (כפי שעשינו עד כה), חריגה בזמן הריצה פשוט עוצרת את התוכנית ומוצגת בה הודעת שגיאה. זוהי התנהגות ברירת מחדל טובה, וראיתם אותה פעמים רבות. כדי לטפל בחריגים, תוכלו להוסיף לקוד מבנה מסוג "try/except" (חריג):

  try:
    ## Either of these two lines could throw an IOError, say
    ## if the file does not exist or the read() encounters a low level error.
    f = open(filename, 'rb')
    data = f.read()
    f.close()
  except IOError:
    ## Control jumps directly to here if any of the above lines throws IOError.
    sys.stderr.write('problem reading:' + filename)
  ## In any case, the code then continues with the line after the try/except

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

HTTP – urllib ו-urlparse

המודול *urllib.request* מספק אחזור כתובות אתרים - ויוצר כתובת אתר שנראה כמו קובץ שניתן לקרוא ממנו. המודול *urlparse* יכול להפריד ולהרכיב כתובות אתרים.

  • מסמכי מודול של urllib.request
  • ufile = urllib.request.urlopen(url) -- מחזיר קובץ כגון אובייקט עבור כתובת אתר זו
  • text = ufile.read() -- יכול לקרוא ממנו, כמו קובץ (readlines() וכו') גם עובד)
  • info = ufile.info() -- המטא מידע של בקשה זו. info.gettype() הוא סוג mime, למשל 'text/html'
  • baseurl = ufile.geturl() -- מקבל את כתובת האתר "base" של הבקשה, שעשויה להיות שונה מהמקורית עקב הפניות מחדש
  • urllib.request.urlretrieve(url, filename) -- מוריד את נתוני כתובת האתר לנתיב הקובץ הנתון
  • urllib.parse.urljoin(baseurl, url) -- בהינתן כתובת URL שעשויה להיות מלאה או לא מלאה, וכתובת ה-base URL של הדף שממנו היא מגיעה מחזירה כתובת URL מלאה. צריך להשתמש ב-geturl() שלמעלה כדי לספק את כתובת ה-URL הבסיסית.

כל החריגים נמצאים ב-urllib.error.

from urllib.request import urlopen

## Given a url, try to retrieve it. If it's text/html,
## print its base url and its text.
def wget(url):
  ufile = urlopen(url)  ## get file-like object for url
  info = ufile.info()   ## meta-info about the url content
  if info.get_content_type() == 'text/html':
    print('base url:' + ufile.geturl())
    text = ufile.read()  ## read all its text
    print(text)

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

אם נראה ש-urlopen() מושעה, ייתכן שהמערכת לא מאפשרת גישה ישירה לכתובות http מסוימות. כדי לבדוק זאת, אפשר לנסות לאחזר את אותה כתובת URL באמצעות wget או curl. אם התוכנות האלה גם נכשלות, צריך לאחזר תוכן http דרך שירות proxy. מערך השיעור הזה לא כולל מידע על הגדרת גישה לשרת proxy.

## Version that uses try/except to print an error message if the
## urlopen() fails.
def wget2(url):
  try:
    ufile = urlopen(url)
    if ufile.info().get_content_type() == 'text/html':
      print(ufile.read())
  except IOError:
    print('problem reading url:', url)

תרגיל

כדי לתרגל את מערכת הקבצים וחומר של פקודות חיצוניות, אפשר לעיין בהעתקת תרגיל מיוחד. כדי לתרגל את החומר הנלמד ב-urllib, אפשר לעיין בLog Puzzle התרגיל.