דילוג לתוכן
פייתון

מה זה set פייתון? המדריך המעשי לרשימות, מילונים וסטים בלי להתבלבל

אם חיפשתם מה זה set פייתון, כנראה שכבר נתקלתם ב־list או dict, ואז הגיע גם set וטרף קצת את הקלפים. שלושת המבנים האלה נראים דומים במבט ראשון: כולם “מחזיקים כמה ערכים”. אבל בפועל הם נועדו לבעיות שונות לגמרי, ובחירה נכונה ביניהם הופכת קוד פייתון לפשוט, מהיר וקריא יותר.

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

רגע לפני הקוד: שלושת המבנים במשפט אחד

בפייתון יש כמה מבני נתונים מובנים, אבל שלושה מהם חוזרים כמעט בכל קובץ קוד:

  • רשימה — list: אוסף מסודר של פריטים, שיכול להכיל כפילויות.
  • מילון — dict: התאמה בין מפתח לערך, כמו שם משתמש למספר נקודות.
  • סט — set: אוסף לא מסודר של ערכים ייחודיים בלבד, בלי כפילויות.

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

מה צריך להכין מראש כדי להריץ את הדוגמאות

כדי להריץ את הדוגמאות במאמר צריך התקנה של Python 3. אפשר לבדוק זאת בשורת הפקודה.

ב־Linux/macOS, ב־bash:

bash
python3 --version

ב־Windows, ב־PowerShell:

powershell
py --version

אם מתקבלת גרסה של Python 3, אפשר ליצור קובץ בשם collections_demo.py ולהריץ אותו. לאורך המאמר הדוגמאות הן קבצים שלמים: מעתיקים, שומרים, ומריצים.

רשימות בפייתון: כשחשוב לשמור סדר

רשימה בפייתון נוצרת עם סוגריים מרובעים: []. היא מתאימה למצבים שבהם יש רצף של פריטים: שמות קבצים, פעולות לביצוע, ציונים, שורות מתוך קובץ, או תוצאות שהתקבלו לפי סדר מסוים.

לרשימה יש כמה תכונות חשובות:

  • היא שומרת על סדר הפריטים.
  • אפשר לגשת לפריט לפי אינדקס, למשל items[0].
  • אפשר להוסיף, להסיר ולשנות פריטים.
  • היא יכולה להכיל כפילויות.

דוגמה מלאה: בניית רשימת משימות וסינון שלה

python
tasks = ["write tests", "fix bug", "write tests", "update docs"]

print("All tasks:")
for task in tasks:
    print("-", task)

tasks.append("run formatter")

print("First task:", tasks[0])
print("Number of tasks:", len(tasks))

unique_ordered_tasks = []
for task in tasks:
    if task not in unique_ordered_tasks:
        unique_ordered_tasks.append(task)

print("Unique tasks in original order:")
for task in unique_ordered_tasks:
    print("-", task)

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

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

מילונים בפייתון: כשצריך מפתח וערך

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

דוגמאות נפוצות:

  • שם משתמש ← מספר התחברויות.
  • שם קובץ ← גודל הקובץ.
  • קוד מוצר ← פרטי מוצר.
  • שם שדה מתוך קובץ JSON ← הערך שלו.

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

דוגמה מלאה: ספירת הופעות של מילים

python
text = "python is fun and python is useful"
words = text.split()

counts = {}

for word in words:
    if word in counts:
        counts[word] += 1
    else:
        counts[word] = 1

print("Word counts:")
for word, count in counts.items():
    print(word, count)

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

bash
Word counts:
python 2
is 2
fun 1
and 1
useful 1

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

מה זה set פייתון ומתי הוא עדיף על רשימה?

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

סט נוצר עם set() או עם סוגריים מסולסלים שמכילים ערכים, למשל {"python", "sql", "linux"}. אבל חשוב לדעת: {} לבד יוצר מילון ריק, לא סט ריק. סט ריק יוצרים עם set().

דוגמה מלאה: הסרת כפילויות ובדיקת חברות

python
languages = ["python", "sql", "python", "javascript", "sql", "linux"]

unique_languages = set(languages)

print("Unique languages:")
for language in unique_languages:
    print(language)

required = {"python", "git"}
known = {"python", "sql", "linux"}

missing = required - known
shared = required & known

print("Missing:", missing)
print("Shared:", shared)
print("Knows python:", "python" in known)

הקוד מתחיל ברשימה שיש בה כפילויות, ממיר אותה לסט, ואז מבצע פעולות קבוצתיות: חיסור בין סטים, חיתוך בין סטים, ובדיקת שייכות. הפלט יציג שפות ייחודיות בלבד. הסדר של השפות בסט לא מובטח, ולכן אין לבנות עליו. בהמשך הפלט יראה ש־git חסר, ש־python משותף, ושבדיקת "python" in known מחזירה True.

טבלת השוואה: list מול dict מול set

מבנה שומר סדר? מאפשר כפילויות? גישה עיקרית שימוש טיפוסי
list כן כן לפי אינדקס או מעבר בלולאה רצף פעולות, תוצאות, פריטים מסודרים
dict כן, לפי סדר ההכנסה בפייתון מודרני מפתחות ייחודיים; ערכים יכולים לחזור לפי מפתח מיפוי מזהים לערכים
set לא כסדר לוגי שאפשר לסמוך עליו לא בדיקת שייכות ופעולות קבוצתיות הסרת כפילויות, חיתוך, איחוד, הפרש

איך בוחרים נכון: תהליך החלטה קצר

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

  1. האם הסדר חשוב? אם כן, התחילו מ־list.
  2. האם צריך לשלוף ערך לפי שם או מזהה? אם כן, כנראה שצריך dict.
  3. האם כל ערך צריך להופיע פעם אחת בלבד? אם כן, בדקו אם set מתאים.
  4. האם צריך לבדוק הרבה פעמים אם ערך קיים? ברוב המקרים סט או מילון יהיו נוחים יותר מרשימה.

למשל, רשימת שמות קבצים שנקראה מתיקייה יכולה להיות list, כי אולי חשוב להציג אותה בסדר מסוים. אבל אם המטרה היא רק לבדוק אם כבר טיפלנו בקובץ מסוים, set של שמות הקבצים שטופלו יהיה ברור יותר.

דוגמה מעשית: עיבוד שורות לנתונים מסודרים

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

python
log_lines = [
    "alice login",
    "bob login",
    "alice upload",
    "alice logout",
    "bob upload",
]

users = set()
actions_by_user = {}

for line in log_lines:
    user, action = line.split()
    users.add(user)

    if user not in actions_by_user:
        actions_by_user[user] = []

    actions_by_user[user].append(action)

print("All log lines:")
for line in log_lines:
    print(line)

print("Users:", users)

print("Actions by user:")
for user, actions in actions_by_user.items():
    print(user, actions)

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

זו גם דרך חשיבה טובה לפני מעבר למסדי נתונים: קודם מבינים מהי “רשומה”, מהו “מפתח”, ואיפה יש כפילויות מותרות או אסורות. בהמשך, אותם רעיונות חוזרים גם ב־SQL ומסדי נתונים, רק עם טבלאות, עמודות ושאילתות.

טעויות נפוצות והודעות שגיאה אמיתיות

שימוש ב־{} כסט ריק

טעות נפוצה היא לחשוב ש־{} יוצר סט ריק. בפועל הוא יוצר מילון ריק.

python
items = {}
items.add("python")

print(items)

הודעת השגיאה תהיה:

output
AttributeError: 'dict' object has no attribute 'add'

התיקון הוא ליצור סט ריק עם set():

python
items = set()
items.add("python")

print(items)

הפלט יהיה סט שמכיל את python. הסדר לא חשוב כאן, כי יש רק איבר אחד.

גישה לרשימה עם אינדקס שלא קיים

ברשימה, אינדקסים מתחילים מ־0. אם יש שלושה פריטים, האינדקסים הם 0, 1, 2. ניסיון לגשת ל־3 ייכשל.

python
names = ["alice", "bob", "carol"]

print(names[3])

הודעת השגיאה תהיה:

output
IndexError: list index out of range

כדי לתקן, בדקו את אורך הרשימה עם len(), או עברו עליה בלולאה במקום לנחש אינדקס:

python
names = ["alice", "bob", "carol"]

for name in names:
    print(name)

שליפת מפתח שלא קיים במילון

במילון, ניסיון לגשת למפתח שלא קיים יגרום לשגיאה.

python
scores = {"alice": 10, "bob": 7}

print(scores["carol"])

הודעת השגיאה תהיה:

output
KeyError: 'carol'

אם לא בטוחים שהמפתח קיים, אפשר להשתמש ב־get():

python
scores = {"alice": 10, "bob": 7}

print(scores.get("carol", 0))

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

הכנסת רשימה לתוך סט

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

python
items = set()
items.add(["python", "sql"])

print(items)

הודעת השגיאה תהיה:

output
TypeError: unhashable type: 'list'

אם צריך לשמור זוג או רצף קטן של ערכים בתוך סט, השתמשו ב־tuple:

python
items = set()
items.add(("python", "sql"))

print(items)

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

מתי לא להשתמש בסט, גם אם הוא נראה נוח

סט מפתה כי הוא מסיר כפילויות בקלות, אבל הוא לא תמיד הבחירה הנכונה. אל תשתמשו בו כאשר:

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

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

שאלות שקוראים באמת שואלים

האם אפשר להמיר בין list, dict ו־set?

כן, אבל צריך להבין מה הולך לאיבוד. המרה מ־list ל־set מסירה כפילויות. המרה מ־set ל־list יוצרת רשימה, אבל לא בהכרח בסדר שרציתם. מילון אפשר להמיר לרשימת מפתחות, רשימת ערכים או רשימת זוגות בעזרת keys(), values() ו־items().

האם dict הוא כמו JSON?

לא בדיוק, אבל הם דומים במראה. מילון הוא אובייקט פייתון בזיכרון. JSON הוא פורמט טקסטואלי להעברת נתונים. בפייתון אפשר להמיר ביניהם בעזרת המודול json מהספרייה הסטנדרטית, אבל לא כל אובייקט פייתון מתאים אוטומטית ל־JSON.

האם set מהיר יותר מ־list?

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

סיכום: לבחור לפי השאלה שהקוד שואל

רשימות, מילונים וסטים הם לא שלוש דרכים שונות לעשות אותו דבר, אלא שלושה כלים לפתרון בעיות שונות. list מתאים לרצף מסודר. dict מתאים למיפוי בין מפתח לערך. set מתאים לייחודיות, בדיקת שייכות ופעולות קבוצתיות.

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