F-strings הן דרך מודרנית ונוחה מאוד להטמיע ערכי משתנים וביטויים ישירות בתוך טקסט של מחרוזת. כדי ליצור f-string, פשוט מציבים את האות f לפני המרכאה הפותחת. בתוך המחרוזת, ניתן להכניס משתנים על ידי עטיפתם בסוגריים מסולסלים {}, ופייתון יחליף אוטומטית את {משתנה} בערכו.
<em># ניצור שני משתנים עם ערכים מספריים.</em>
one = 1
two = 2
<em># נכניס את ערכי המשתנים 'one' ו-'two' לתוך המחרוזת.</em>
f"{one}, {two}"
<em># פלט: '1, 2'</em>
הכוח של f-strings טמון ביכולתם להכיל לא רק משתנים, אלא כמעט כל ביטוי פייתון תקין בתוך הסוגריים. זה מאפשר לבצע חישובים "על הדרך" מבלי ליצור משתני ביניים מיותרים.
<em># נבצע חיבור ישירות בתוך ה-f-string.</em>
f"{one} + {two} = {one + two}"
<em># פלט: '1 + 2 = 3'</em>
ניתן לגשת בקלות לאלמנטים ממבני נתונים כמו מילונים (לפי מפתח) ורשימות (לפי אינדקס) מתוך f-string. הדבר נכון גם לגבי גישה לתכונות של אובייקטים (באמצעות סימון נקודה) ואפילו לקריאה לפונקציות.
<em># גישה לערך במילון לפי מפתח.</em>
colors = {"red": "#ff0000", "green": "#00ff00"}
f"הצבע האדום הוא {colors['red']}"
<em># פלט: 'הצבע האדום הוא #ff0000'</em>
<em># גישה לאלמנטים ברשימה לפי אינדקס.</em>
data = [4, 8, 15, 16, 23, 42]
f"המספרים הטובים ביותר: {data[4]} ו-{data[5]}"
<em># פלט: 'המספרים הטובים ביותר: 23 ו-42'</em>
<em># גישה לתכונות אובייקט וקריאה לפונקציות.</em>
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
pos = Point(23, 42)
f"מיקום: {pos.x}, {pos.y}. הערך הגדול יותר הוא {max(pos.x, pos.y)}."
<em># פלט: 'מיקום: 23, 42. הערך הגדול יותר הוא 42.'</em>
שימוש ב-f-strings לדיבוג
החל מפייתון 3.8, f-strings כוללות כלי רב עוצמה לדיבוג מהיר. על ידי הוספת סימן שוויון (=) אחרי משתנה או ביטוי בתוך הסוגריים המסולסלים, אתם מורים לפייתון להדפיס לא רק את הערך, אלא גם את הביטוי עצמו. זהו כלי שימושי להפליא לבדיקת קוד.
from datetime import date, timedelta
user = "eric_idle"
member_since = date(1975, 7, 31)
delta = date(2022, 4, 11) - member_since
<em># השתמשו ב-f"{user=}" כדי לקבל אוטומטית "user='eric_idle'".</em>
f"{user=} {member_since=}"
<em># פלט: "user='eric_idle' member_since=datetime.date(1975, 7, 31)"</em>
ניתן לשלב את מפרט הדיבוג הזה עם מפרטי עיצוב רגילים. אפשר גם להשתמש בו על ביטויים שלמים כדי להציג בבירור גם את החישוב וגם את תוצאתו.
<em># = מציג את שם המשתנה, : מתחיל עיצוב, ,d מעצב כמספר שלם עם מפריד אלפים.</em>
f"{delta.days=:,d}"
<em># פלט: 'delta.days=17,056'</em>
<em># מציג גם את הקלט וגם את תוצאת החישוב.</em>
from math import cos, radians
theta = 30
f"{theta=} {cos(radians(theta))=:.3f}"
<em># פלט: 'theta=30 cos(radians(theta))=0.866'</em>
הדפסת ייצוגי דיבוג (repr)
לאובייקטים בפייתון יש שני ייצוגי מחרוזת: str() (לפלט ידידותי למשתמש) ו-repr() (לפלט חד-משמעי, ידידותי למפתח). כברירת מחדל, f-strings משתמשות ב-str(). כדי לקבל את פלט repr(), ניתן להשתמש בדגל ההמרה !r, המהווה קיצור דרך נוח לקריאה ידנית ל-repr(). הדגל !s קורא במפורש ל-str().
class Data:
def __repr__(self): return '<Data ...>' <em># ייצוג לדיבוג</em>
def __str__(self): return 'string representation' <em># ייצוג למשתמש</em>
data = Data()
<em># התנהגות ברירת המחדל קוראת ל-str(data)</em>
f"data: {data}"
<em># פלט: 'data: string representation'</em>
<em># שימוש בדגל !r קורא ל-repr(data)</em>
f"data: {data!r}"
<em># פלט: 'data: <Data ...>'</em>
ריפוד, יישור וחיתוך
F-strings מספקות שליטה מלאה על עיצוב הפלט, כולל רוחב השדה, יישור ותווי מילוי. מפרט העיצוב מופיע אחרי נקודתיים (:).
>מיישר את הטקסט לימין.<מיישר את הטקסט לשמאל.^ממקם את הטקסט במרכז.- מספר אחרי תו היישור מציין את הרוחב הכולל של השדה.
- תו לפני תו היישור מציין את תו המילוי.
val = "test"
<em># יישור לימין בשדה ברוחב 10 תווים</em>
f"{val:>10}"
<em># פלט: ' test'</em>
<em># יישור לשמאל ומילוי הרווח הריק בתו '_'</em>
f"{val:_<10}"
<em># פלט: 'test______'</em>
<em># מרכוז הטקסט</em>
f"{val:^10}"
<em># פלט: ' test '</em>
כדי לחתוך מחרוזת לאורך מקסימלי, השתמשו בתחביר :.N, כאשר N הוא מספר התווים.
instrument = "xylophone"
<em># חיתוך המחרוזת ל-5 תווים.</em>
f"{instrument:.5}"
<em># פלט: 'xylop'</em>
ייצוגי מספרים
קיימות אפשרויות עיצוב רבות למספרים. ניתן להמיר בקלות מספרים לבסיס בינארי (b), אוקטלי (o), או הקסדצימלי (x/X). שימוש ב-# מוסיף את הקידומת המתאימה (0b, 0o, 0x).
answer = 42
<em># ייצוג הקסדצימלי</em>
f"{answer:x}, {answer:X}"
<em># פלט: '2a, 2A'</em>
<em># עם קידומת</em>
f"{answer:#x}"
<em># פלט: '0x2a'</em>
<em># סימון מדעי</em>
f"{answer ** 8:e}"
<em># פלט: '9.682652e+12'```</em>
ריפוד מספרים באפסים מובילים נעשה באמצעות `0` כתו מילוי. עבור מספרים עשרוניים (float), ניתן לשלוט הן ברוחב הכולל והן במספר הספרות אחרי הנקודה. ניתן גם לשלוט בהצגת הסימן ולהוסיף מפרידי אלפים.
```python
<em># ריפוד ל-4 ספרות עם אפסים מובילים</em>
f"{answer:04d}"
<em># פלט: '0042'</em>
<em># עבור פאי: רוחב כולל 6, 2 ספרות אחרי הנקודה, ריפוד באפסים</em>
import math
f"{math.pi:06.2f}"
<em># פלט: '003.14'</em>
<em># הצגת הסימן תמיד (+ לחיוביים, - לשליליים)</em>
f"{answer:+d}"
<em># פלט: '+42'</em>
<em># שימוש בפסיק כמפריד אלפים</em>
num = 1234567890
f"{num:,d}"
<em># פלט: '1,234,567,890'</em>
נושאים נוספים ושיטות עבודה מומלצות
לאובייקטים מובנים רבים, כמו datetime, יש שפת עיצוב מיניאטורית משלהם שעובדת ישירות בתוך f-strings.
from datetime import datetime
dt = datetime(2022, 4, 11, 13, 37)
<em># שימוש בקודי עיצוב סטנדרטיים לתאריך/שעה</em>
f"{dt:%Y-%m-%d %H:%M}"
<em># פלט: '2022-04-11 13:37'</em>
מפרטי העיצוב עצמם אינם חייבים להיות סטטיים! ניתן להגדיר אותם באופן דינמי באמצעות משתנים עם סוגריים מסולסלים מקוננים.
<em># רוחב ויישור מוגדרים על ידי משתנים</em>
value = "test"
align = "^"
width = 10
<em># f'{value:{align}{width}}' הופך תחילה ל-f'{value:^10}'</em>
f'{value:{align}{width}}'
<em># פלט: ' test '</em>
אם אתם צריכים לכלול סוגר מסולסל { או } כתו רגיל במחרוזת, פשוט הכפילו אותו.
f"סוגריים מסולסלים רגילים: {{value}}"
<em># פלט: 'סוגריים מסולסלים רגילים: {value}'</em>
עצות מעשיות ומהמורות
קריאות מול קיצור
F-strings מאפשרות להטמיע ביטויים מורכבים מאוד, אך זה לא תמיד רעיון טוב. עיקרון ליבה של פייתון הוא קריאות הקוד.
פרקטיקה גרועה (קשה לקריאה):
<em># טכנית זה עובד, אבל מה קורה כאן?</em>
print(f"תוצאה: {round([user.height for user in users if user.active][0] / 2.54, 2)} אינצ'ים.")
פרקטיקה טובה (הפרדת לוגיקה מהצגה):
<em># 1. תחילה, נכין את הנתונים</em>
active_users_heights = [user.height for user in users if user.active]
first_user_height_cm = active_users_heights[0]
height_in_inches = round(first_user_height_cm / 2.54, 2)
<em># 2. לאחר מכן, נעצב את התוצאה</em>
print(f"תוצאה: {height_in_inches} אינצ'ים.")
הקוד ארוך יותר, אך כעת הוא מובן, ניתן לבדיקה וקל לשינוי. כלל אצבע: אם ביטוי בתוך {} ארוך יותר מ-20-30 תווים או מכיל לוגיקה מורכבת, עדיף להוציא אותו למשתנה נפרד.
F-strings מרובות שורות
עבור מחרוזות ארוכות או ליצירת טקסט מרובה שורות (למשל, שאילתות SQL, תבניות HTML), השתמשו במרכאות משולשות. גם הביטויים שבתוכן יכולים להתפרס על פני מספר שורות.
user = "hypo69"
permissions = ['read', 'write', 'execute']
<em># הביטוי בתוך ה-f-string מחולק למספר שורות למען הקריאות</em>
report = f"""
דוח משתמש: {user.upper()}
----------------------------------
הרשאות: {', '.join(p for p in permissions
if p != 'execute')}
"""
print(report)
שיקולי אבטחה (חשוב מאוד!)
F-strings כשלעצמן בטוחות. ביטוי כמו f"שלום, {name}" אינו מהווה פגיעות; פייתון פשוט לוקח את הייצוג המחרוזתי של name.
הסכנה מתעוררת כאשר משלבים f-strings עם פונקציות המריצות קוד, כמו eval().
קוד מסוכן ביותר — לעולם אל תעשו זאת:
import os
user_template = input("הכנס תבנית: ") <em># המשתמש מזין: '{os.system("reboot")}'</em>
eval(f'f"{user_template}"')
אם משתמש יזין {os.system("reboot")}, השרת שלכם יאתחל את עצמו. זוהי פגיעות של הרצת קוד מרחוק (RCE). לעולם אל תעבירו מחרוזות שסופקו על ידי משתמש לפונקציות כמו eval(), אפילו לא דרך f-strings. עבור תבניות המוגדרות על ידי משתמש, השתמשו במנועי תבניות בטוחים כמו Jinja2.
ביצועים: מדוע f-strings כל כך מהירות?
F-string אינה קריאה לפונקציה; היא חלק מהתחביר של פייתון. המהדר (compiler) מנתח את ה-f-string ומפרק אותו לחלקים מילוליים ולביטויים שיש לחשב. זה מתקמפל לקוד בייט (bytecode) יעיל ביותר שבונה את המחרוזת הסופית בפעולה מהירה אחת. זה הרבה יותר מהר ממתודת .format(), שצריכה לנתח את מחרוזת העיצוב בזמן ריצה.
כלי מיגרציה
כלים כמו flynt ו-pyupgrade יכולים להמיר אוטומטית קוד ישן המשתמש ב-.format() ו-% ל-f-strings מודרניות, וזו דרך מצוינת למדרג במהירות בסיס קוד ותיק.