לדלג לתוכן

מדריך ל-pathlib בפייתון - הדרך הנכונה לעבוד עם נתיבי קבצים

בואו נדבר בכנות. אם למדתם פייתון מסרטון ישן, כנראה שלימדו אתכם לבנות נתיבי קבצים עם שרשור מחרוזות - folder + "/" + filename. זה עובד, עד שמישהו מריץ את הקוד שלכם בווינדוס, ופתאום כל הנתיבים שבורים כי שם מפריד התיקיות הוא \ ולא /. מודול pathlib נולד בדיוק בשביל לפתור את הכאב הזה, וכדאי לכם לאמץ אותו כברירת מחדל.

למה לא פשוט להשתמש במחרוזות

הבעיה עם נתיבים כמחרוזות היא שהן לא "יודעות" שהן נתיבים. אין להן פעולות מובנות לבדוק אם קובץ קיים, לחלץ את הסיומת, או לעבור בין תיקיות בלי לדפוק את עצמכם עם הסלאשים הנכונים. גם המודול הישן os.path עוזר קצת, אבל הוא מבוסס על פונקציות שמקבלות מחרוזות ומחזירות מחרוזות, מה שהופך שרשור פעולות למסורבל.

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

from pathlib import Path

p = Path("data") / "reports" / "2026.csv"
print(p)

שימו לב לתו ה-/ בין החלקים. זה לא חילוק - pathlib מטעין (overload) את האופרטור הזה כדי לבנות נתיבים בצורה שקריאה כמעט כמו הנתיב עצמו, וזה עובד נכון גם בווינדוס וגם בלינוקס ובמאק, כי Path יודע להתאים את עצמו למערכת ההפעלה שעליה הוא רץ.

בדיקות בסיסיות על קבצים ותיקיות

אחת הסיבות שהמודול כל כך נוח היא שכל השאלות הנפוצות על קובץ הן מתודה אחת:

p = Path("data/reports/2026.csv")

print(p.exists())    # האם הנתיב קיים בכלל
print(p.is_file())   # האם זה קובץ
print(p.is_dir())    # האם זו תיקייה
print(p.name)        # "2026.csv"
print(p.suffix)      # ".csv"
print(p.stem)        # "2026", בלי הסיומת
print(p.parent)      # התיקייה שמכילה אותו

אין צורך לזכור שם פונקציה נפרד לכל שאלה כמו ב-os.path - כל המידע יושב על האובייקט עצמו.

יצירת תיקיות וקריאה וכתיבה של קבצים

יצירת תיקייה חדשה, כולל כל התיקיות שבדרך אליה, זה שורה אחת:

Path("data/reports").mkdir(parents=True, exist_ok=True)

הפרמטר parents=True יוצר גם תיקיות ביניים שלא קיימות עדיין, ו-exist_ok=True מונע שגיאה אם התיקייה כבר קיימת - בלי זה, הקוד יזרוק שגיאה בכל פעם שתריצו אותו פעם שנייה.

וקריאה או כתיבה של קובץ טקסט לא דורשת יותר open ו-with בכל פעם שרוצים רק לקרוא הכל:

p = Path("notes.txt")
p.write_text("שלום עולם", encoding="utf-8")
content = p.read_text(encoding="utf-8")
print(content)

write_text ו-read_text פותחים את הקובץ, כותבים או קוראים, וסוגרים אותו - הכל בקריאה אחת. יש גם write_bytes ו-read_bytes לקבצים בינאריים.

חיפוש קבצים עם glob

אחת התכונות השימושיות ביותר היא חיפוש קבצים לפי תבנית, בעזרת glob:

reports_folder = Path("data/reports")

for file in reports_folder.glob("*.csv"):
    print(file)

for file in reports_folder.rglob("*.csv"):
    print(file)  # rglob מחפש גם בתיקיות משנה, רקורסיבית

זה שימושי מאוד כשצריך לעבור על כל הקבצים מסוג מסוים בתיקייה, בלי לכתוב לוגיקה משלכם עם os.walk.

דוגמה מלאה

בואו נחבר הכל לדוגמה קטנה שמחפשת את כל קבצי ה-txt בתיקייה, וכותבת סיכום לקובץ חדש:

from pathlib import Path

source_folder = Path("logs")
summary_file = source_folder / "summary.txt"

lines_total = 0
for log_file in source_folder.glob("*.txt"):
    if log_file.name == "summary.txt":
        continue
    text = log_file.read_text(encoding="utf-8")
    lines_total += len(text.splitlines())

summary_file.write_text(f"סה\"כ שורות בכל הקבצים: {lines_total}", encoding="utf-8")

שימו לב כמה קריא הקוד - כל שורה אומרת בדיוק מה היא עושה, בלי שרשור מחרוזות ובלי לבדוק ידנית איפה נגמרת תיקייה ואיפה מתחיל שם קובץ.

מתי בכל זאת להישאר עם מחרוזות

לפעמים, כשאתם רק מדפיסים נתיב או מעבירים אותו כפרמטר לפקודת מערכת חיצונית, מחרוזת פשוטה מספיקה, ו-pathlib יודע להמיר את עצמו למחרוזת בקלות עם str(p). אבל בכל מקום שבו אתם בונים, בודקים, או עוברים על נתיבים, pathlib פשוט חוסך שגיאות שיצוצו רק כשמישהו ירוץ את הקוד על מערכת הפעלה אחרת מזו שלכם.

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

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

הצטרפו לקהילה בדיסקורד