ar
Feedback
ToCode

ToCode

الذهاب إلى القناة على Telegram

טיפים קצרים למתכנתים מאת ינון פרק

إظهار المزيد
1 420
المشتركون
+124 ساعات
+17 أيام
-430 أيام
أرشيف المشاركات
ToCode
1 420
חמש דוגמאות קצרות לשימוש ב cat effect בסקאלה המנגנון המובנה בסקאלה לתכנות אסינכרוני נקרא Future, והוא קצת מזכיר את Promise של JavaScript. הבעיה של הרבה אנשים עם Future היא שהוא מייצג תוצאה עתידית ולא חישוב עתידי. זה אומר שאם יש לי Future ביד אני לא יכול להריץ אותו כמה פעמים (כי החישוב כבר רץ). מסיבה זאת נוצרו הרבה ספריות הרחבה לשפה שמאפשרות לייצר חישוב עתידי בצורה פונקציונאלית וללא Side Effects. אחת הפופולריות היא cats effect והנה חמש דוגמאות ראשונות שכתבתי עם הספריה. שלום עולם תוכנית סקאלה ראשונה עם cat effect היא כמובן פונקציה שמדפיסה שלום עולם:
  def demo1(): IO[ExitCode] =
    IO.println("Hello WOrld") >> IO.pure(ExitCode.Success)
הרעיון הראשון החדש כאן הוא שפונקציה שאפשר להריץ בצורה אסינכרונית זה בעצם פונקציה שמחזירה IO, וזה נקרא אפקט. לכן הפונקציה demo1 שמחזירה IO[ExitCode] מתאימה להרצה בצורה אסינכרונית. הסימן >> הוא דרך לחבר שני אפקטים ולהחזיר רק את התוצאה של השני, הפונקציה IO.println מייצרת אפקט שמדפיס למסך ו IO.pure מייצרת אפקט שמחזיר ערך קבוע (וכן אפשר לחשוב על אפקט בתור Promise אבל זה טיפה יותר מסובך כי אפקט אפשר גם לבטל). שלום עולם עם המתנה עכשיו שהבנו את הסיפור של אפקטים אפשר להמשיך ולראות איך מחברים אותם. דרך אחת לחבר אפקטים היא סימן ה >> שכבר פגשנו ואפשר לקחת אותו עוד צעד קדימה. הפונקציה IO.sleep מחזירה אפקט שמחכה, ולכן הקוד הבא:
  def demo11(): IO[ExitCode] =
    IO.sleep(1000.millis) >> IO.println("1") >>
    IO.sleep(1000.millis) >> IO.println("2") >>
    IO.sleep(1000.millis) >> IO.println("3") >>
    IO.pure(ExitCode.Success)
מייצר אפקט שמחכה שניה, מדפיס 1, מחכה עוד שניה, מדפיס 2, מחכה עוד שניה, מדפיס 3 ואז מחזיר הצלחה. דרך אחרת וקצת יותר ידידותית בסקאלה לכתוב אותו היא:
  def demo2(): IO[ExitCode] =
    for {
      _ <- IO.sleep(1000.millis) >> IO.println("1")
      _ <- IO.sleep(1000.millis) >> IO.println("2")
      _ <- IO.sleep(1000.millis) >> IO.println("3")
    } yield ExitCode.Success
וזו גם מאפשרת לכל אפקט להשתמש בתוצאה של האפקט שלפניו, למרות שבדוגמה הפעם לא עשיתי את זה והתעלמתי מהתוצאה של האפקט הקודם, בכך שנתתי לה את השם _. שלום עולם במקביל אחרי שאנחנו מבינים איך להגדיר מספר אפקטים הצעד הבא הוא להריץ אותם במקביל, בדומה ל Promise.all. ב cats effect זה קורה עם פונקציה בשם parSequence:
  def demo3(): IO[ExitCode] =
    List(
      IO.sleep(1000.millis) >> IO.println("1"),
      IO.sleep(1000.millis) >> IO.println("2"),
      IO.sleep(1000.millis) >> IO.println("3")
    ).parSequence >> IO.pure(ExitCode.Success)
הפעם הקוד מגדיר רשימה של 3 אפקטים ומפעיל על הרשימה את parSequence. התוצאה היא הפעלה של שלושת האפקטים במקביל כך שאחרי שניה יודפסו שלוש ההודעות בסדר אקראי. משיכת מידע מהרשת ספריות הרחבה רבות של סקאלה שקשורות ל IO כוללת גירסה מותאמת ל cats effect, לדוגמה הספריה sttp שיודעת לשלוח בקשות HTTP. הקוד הבא בסקאלה מחזיר אפקט שפונה ל URL (בדוגמה שלי זה https://icanhazdadjoke.com/) ומחזיר את גוף התשובה בתור מחרוזת:
def randomDadJoke(): IO[String] =
  HttpClientCatsBackend.resource[IO]().use { backend =>
    basicRequest
      .header("Accept", "application/json")
      .get(uri"https://icanhazdadjoke.com/")
      .response(asString)
      .send(backend)
      .map {response => response.body.right.get}
  }
הדבר החשוב לשים לב הוא ערך ההחזרה של הפונקציה שזה IO[String] כלומר מדובר באפקט שיחזיר מחרוזת. אפשר להשתמש באפקט זה כדי להדפיס את התשובה:
  def demo4(): IO[ExitCode] =
    randomDadJoke().map(s => println(s)) >> IO.pure(ExitCode.Success)
משיכת מידע מהרשת במקביל וכמובן אחרי שיש אפקט אפשר להריץ אותו במקביל כדי לקבל מספר בדיחות:
  def demo5(): IO[ExitCode] =
    List(
      randomDadJoke().map(s => println(s)),
      randomDadJoke().map(s => println(s)),
      randomDadJoke().map(s => println(s))
    ).parSequence >> IO.pure(ExitCode.Success)

ToCode
1 420
)\.parSequence \>\> IO\.pure(ExitCode\.Success)

ToCode
1 420
חמש דוגמאות קצרות לשימוש ב cat effect בסקאלה המנגנון המובנה בסקאלה לתכנות אסינכרוני נקרא Future, והוא קצת מזכיר את Promise של JavaScript\. הבעיה של הרבה אנשים עם Future היא שהוא מייצג תוצאה עתידית ולא חישוב עתידי\. זה אומר שאם יש לי Future ביד אני לא יכול להריץ אותו כמה פעמים (כי החישוב כבר רץ)\. מסיבה זאת נוצרו הרבה ספריות הרחבה לשפה שמאפשרות לייצר חישוב עתידי בצורה פונקציונאלית וללא Side Effects\. אחת הפופולריות היא cats effect והנה חמש דוגמאות ראשונות שכתבתי עם הספריה\. שלום עולם תוכנית סקאלה ראשונה עם cat effect היא כמובן פונקציה שמדפיסה שלום עולם:

  def demo1(): IO[ExitCode] \=

    IO\.println("Hello WOrld") \>\> IO\.pure(ExitCode\.Success)

הרעיון הראשון החדש כאן הוא שפונקציה שאפשר להריץ בצורה אסינכרונית זה בעצם פונקציה שמחזירה IO, וזה נקרא אפקט\. לכן הפונקציה demo1 שמחזירה IO[ExitCode] מתאימה להרצה בצורה אסינכרונית\. הסימן \>\> הוא דרך לחבר שני אפקטים ולהחזיר רק את התוצאה של השני, הפונקציה IO\.println מייצרת אפקט שמדפיס למסך ו IO\.pure מייצרת אפקט שמחזיר ערך קבוע (וכן אפשר לחשוב על אפקט בתור Promise אבל זה טיפה יותר מסובך כי אפקט אפשר גם לבטל)\. שלום עולם עם המתנה עכשיו שהבנו את הסיפור של אפקטים אפשר להמשיך ולראות איך מחברים אותם\. דרך אחת לחבר אפקטים היא סימן ה \>\> שכבר פגשנו ואפשר לקחת אותו עוד צעד קדימה\. הפונקציה IO\.sleep מחזירה אפקט שמחכה, ולכן הקוד הבא:

  def demo11(): IO[ExitCode] \=

    IO\.sleep(1000\.millis) \>\> IO\.println("1") \>\>

    IO\.sleep(1000\.millis) \>\> IO\.println("2") \>\>

    IO\.sleep(1000\.millis) \>\> IO\.println("3") \>\>

    IO\.pure(ExitCode\.Success)

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

  def demo2(): IO[ExitCode] \=

    for {

      _ <\- IO\.sleep(1000\.millis) \>\> IO\.println("1")

      _ <\- IO\.sleep(1000\.millis) \>\> IO\.println("2")

      _ <\- IO\.sleep(1000\.millis) \>\> IO\.println("3")

    } yield ExitCode\.Success

וזו גם מאפשרת לכל אפקט להשתמש בתוצאה של האפקט שלפניו, למרות שבדוגמה הפעם לא עשיתי את זה והתעלמתי מהתוצאה של האפקט הקודם, בכך שנתתי לה את השם _\. שלום עולם במקביל אחרי שאנחנו מבינים איך להגדיר מספר אפקטים הצעד הבא הוא להריץ אותם במקביל, בדומה ל Promise\.all\. ב cats effect זה קורה עם פונקציה בשם parSequence:

  def demo3(): IO[ExitCode] \=

    List(

      IO\.sleep(1000\.millis) \>\> IO\.println("1"),

      IO\.sleep(1000\.millis) \>\> IO\.println("2"),

      IO\.sleep(1000\.millis) \>\> IO\.println("3")

    )\.parSequence \>\> IO\.pure(ExitCode\.Success)

הפעם הקוד מגדיר רשימה של 3 אפקטים ומפעיל על הרשימה את parSequence\. התוצאה היא הפעלה של שלושת האפקטים במקביל כך שאחרי שניה יודפסו שלוש ההודעות בסדר אקראי\. משיכת מידע מהרשת ספריות הרחבה רבות של סקאלה שקשורות ל IO כוללת גירסה מותאמת ל cats effect, לדוגמה הספריה sttp שיודעת לשלוח בקשות HTTP\. הקוד הבא בסקאלה מחזיר אפקט שפונה ל URL (בדוגמה שלי זה https://icanhazdadjoke\.com/) ומחזיר את גוף התשובה בתור מחרוזת:

def randomDadJoke(): IO[String] \=

  HttpClientCatsBackend\.resource[IO]()\.use { backend \=\>

    basicRequest

      \.header("Accept", "application/json")

      \.get(uri"https://icanhazdadjoke\.com/")

      \.response(asString)

      \.send(backend)

      \.map {response \=\> response\.body\.right\.get}

  }

הדבר החשוב לשים לב הוא ערך ההחזרה של הפונקציה שזה IO[String] כלומר מדובר באפקט שיחזיר מחרוזת\. אפשר להשתמש באפקט זה כדי להדפיס את התשובה:

  def demo4(): IO[ExitCode] \=

    randomDadJoke()\.map(s \=\> println(s)) \>\> IO\.pure(ExitCode\.Success)

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

  def demo5(): IO[ExitCode] \=

    List(

      randomDadJoke()\.map(s \=\> println(s)),

      randomDadJoke()\.map(s \=\> println(s)),

      randomDadJoke()\.map(s \=\> println(s))

ToCode
1 420
# חמש דוגמאות קצרות לשימוש ב cat effect בסקאלה סקאלה לא כוללת מנגנון תחבירי מובנה לקוד אסינכרוני וכך נוצרו ספריות הרחבה רבות שמנסות לגשר על הפער. cat effect היא ספריה פופולרית כזו שנראית גמישה ומתוחזקת, אבל לא בטוח כמה פשוטה ללימוד. הנה חמש דוגמאות יחסית פשוטות שעזרו לי להתחיל. ## שלום עולם תוכנית סקאלה ראשונה עם cat effect היא כמובן פונקציה שמדפיסה שלום עולם:
  def demo1(): IO[ExitCode] =
    IO.println("Hello WOrld") >> IO.pure(ExitCode.Success)
הרעיון הראשון החדש כאן הוא שפונקציה שאפשר להריץ בצורה אסינכרונית זה בעצם פונקציה שמחזירה IO, וזה נקרא אפקט. לכן הפונקציה demo1 שמחזירה IO[ExitCode] מתאימה להרצה בצורה אסינכרונית. הסימן >> הוא דרך לחבר שני אפקטים ולהחזיר רק את התוצאה של השני, הפונקציה IO.println מייצרת אפקט שמדפיס למסך ו IO.pure מייצרת אפקט שמחזיר ערך קבוע (וכן אפשר לחשוב על אפקט בתור Promise אבל זה טיפה יותר מסובך כי אפקט אפשר גם לבטל). ## שלום עולם עם המתנה עכשיו שהבנו את הסיפור של אפקטים אפשר להמשיך ולראות איך מחברים אותם. דרך אחת לחבר אפקטים היא סימן ה >> שכבר פגשנו ואפשר לקחת אותו עוד צעד קדימה. הפונקציה IO.sleep מחזירה אפקט שמחכה, ולכן הקוד הבא:
  def demo11(): IO[ExitCode] =
    IO.sleep(1000.millis) >> IO.println("1") >>
    IO.sleep(1000.millis) >> IO.println("2") >>
    IO.sleep(1000.millis) >> IO.println("3") >>
    IO.pure(ExitCode.Success)
מייצר אפקט שמחכה שניה, מדפיס 1, מחכה עוד שניה, מדפיס 2, מחכה עוד שניה, מדפיס 3 ואז מחזיר הצלחה. דרך אחרת וקצת יותר ידידותית בסקאלה לכתוב אותו היא:
  def demo2(): IO[ExitCode] =
    for {
      _ <- IO.sleep(1000.millis) >> IO.println("1")
      _ <- IO.sleep(1000.millis) >> IO.println("2")
      _ <- IO.sleep(1000.millis) >> IO.println("3")
    } yield ExitCode.Success
וזו גם מאפשרת לכל אפקט להשתמש בתוצאה של האפקט שלפניו, למרות שבדוגמה הפעם לא עשיתי את זה והתעלמתי מהתוצאה של האפקט הקודם, בכך שנתתי לה את השם _. ## שלום עולם במקביל אחרי שאנחנו מבינים איך להגדיר מספר אפקטים הצעד הבא הוא להריץ אותם במקביל, בדומה ל Promise.all. ב cats effect זה קורה עם פונקציה בשם parSequence:
  def demo3(): IO[ExitCode] =
    List(
      IO.sleep(1000.millis) >> IO.println("1"),
      IO.sleep(1000.millis) >> IO.println("2"),
      IO.sleep(1000.millis) >> IO.println("3")
    ).parSequence >> IO.pure(ExitCode.Success)
הפעם הקוד מגדיר רשימה של 3 אפקטים ומפעיל על הרשימה את parSequence. התוצאה היא הפעלה של שלושת האפקטים במקביל כך שאחרי שניה יודפסו שלוש ההודעות בסדר אקראי. ## משיכת מידע מהרשת ספריות הרחבה רבות של סקאלה שקשורות ל IO כוללת גירסה מותאמת ל cats effect, לדוגמה הספריה sttp שיודעת לשלוח בקשות HTTP. הקוד הבא בסקאלה מחזיר אפקט שפונה ל URL (בדוגמה שלי זה https://icanhazdadjoke.com/) ומחזיר את גוף התשובה בתור מחרוזת:
def randomDadJoke(): IO[String] =
  HttpClientCatsBackend.resource[IO]().use { backend =>
    basicRequest
      .header("Accept", "application/json")
      .get(uri"https://icanhazdadjoke.com/")
      .response(asString)
      .send(backend)
      .map {response => response.body.right.get}
  }
הדבר החשוב לשים לב הוא ערך ההחזרה של הפונקציה שזה IO[String] כלומר מדובר באפקט שיחזיר מחרוזת. אפשר להשתמש באפקט זה כדי להדפיס את התשובה:
  def demo4(): IO[ExitCode] =
    randomDadJoke().map(s => println(s)) >> IO.pure(ExitCode.Success)
## משיכת מידע מהרשת במקביל וכמובן אחרי שיש אפקט אפשר להריץ אותו במקביל כדי לקבל מספר בדיחות:
  def demo5(): IO[ExitCode] =
    List(
      randomDadJoke().map(s => println(s)),
      randomDadJoke().map(s => println(s)),
      randomDadJoke().map(s => println(s))
    ).parSequence >> IO.pure(ExitCode.Success)

ToCode
1 420
# סוף הדרך לפרויקט תוכנה, סוף הדרך הוא הנקודה שאף אחד כבר לא רוצה או יכול להמשיך לעבוד על הפרויקט הזה ואין סיכוי לראות בו פיצ'רים חדשים. הנה כמה מאפיינים משותפים שראיתי בפרויקטים שהגיעו לשלב הזה: 1. תשתיות (תלויות, בסיסי נתונים, שרתים) ישנות. למעשה כל כך ישנות שאין אומץ או יכולת לשדרג אותן. 2. קושי לגייס מתכנתים. בדרך כלל בגלל שפת תכנות ישנה או חדשה מדי. 3. היעדר תשתית בדיקות למוצר וותיק. כל שורת קוד שתוסיף תפגע בפונקציונאליות שמישהו איפשהו צריך. 4. חוסר יכולת לבנות את הפרויקט על מכונת פיתוח רגילה. דרישה להתקנות מיוחדות או תהליכי בניה מיוחדים. הרבה פעמים פרויקט מגיע לסוף הדרך בגלל אפקט כדור שלג - אנחנו מנסים להתקדם בפיתוח, אבל בעיות תשתית גורמות לנו לעבוד יותר קשה על כל צעד, וההתקדמות האיטית מכריחה אותנו להשקיע יותר זמן בפיצ'רים החדשים במקום לפתור את בעיות התשתית. מתישהו מגיעה הנקודה שלכתוב את הפרויקט מחדש כבר יהיה יותר קל מלהוסיף עוד פיצ'ר. זה סוף הדרך.

ToCode
1 420
# אופס הכנסתי קונסטריינט לפני כמה שבועות התחלתי ללמוד גרמלין וגם פרסמתי כאן פוסט עם כמה דוגמאות קוד, אחת מהן היתה:
def createPost(g: GraphTraversalSource, slug: String, title: String, publishedAt: String): Vertex =
  g.addV("post")
    .property("slug", slug)
    .property("title", title)
    .property("publishedAt", LocalDateTime.parse(publishedAt, formatter))
    .next()
זה נראה תמים - הקוד יוצר צומת, מגדיר שלושה מאפיינים ושומר. ועל הדרך מוסיף מגבלה משמעותית למערכת שלנו. גרמלין היא שפת שאילתות ואפשר להשתמש בה כדי לתשאל בסיסי נתונים מרוחקים (למשל neptune שרץ בענן של AWS או קוסמוס שרץ באז'ור או ארקייד דיבי שרץ על מכונה שלכם), ובנוסף כדי לגשת לבסיסי נתונים בזיכרון שרצים באותו JVM כמו התוכנית. בדוגמת הקוד שפרסמתי הגדרתי בסיס נתונים מוטמע שרץ בזיכרון באותו JVM כמו של התוכנית, ולכן אין בעיה לשמור אוביקטים מתוחכמים כמו תאריך באותו בסיס נתונים. ניסיון להעביר את הקוד לנפטון או בסיס נתונים מרוחק אחר ייכשל, כי גרמלין לא עושה סריאליזציה אוטומטית לתאריכים. הכנסת קונסטריינטים (והסרתם) היא חלק טבעי מלימוד ומפיתוח מערכות בטכנולוגיות שלא עבדנו בהן בעבר. יש לזה כל מיני סיבות, בדוגמה שלי עם גרמלין חשבתי בהתחלה לבנות מערכת עם בסיס נתונים מוטמע ורק אחר כך הבנתי שעדיף לשמור את בסיס הנתונים בענן (מה שהוביל לגילוי כל האילוצים הנסתרים). זו אחת הסיבות שקשה לתת הערכות זמנים בפיתוח, ובמיוחד בפיתוח עם טכנולוגיות חדשות. באותה נשימה צריך להגיד שהרבה פעמים שימוש ב Best Practices רגילים של פיתוח יכול להגן עלינו מחלק מהסיכונים. במקרה של הסריאליזציה של תאריכים, הקפדה על כתיבת שאילתות רק במקומות ספציפיים בקוד יכולה לעזור. במערכת אידאלית תיקון הקוד כך שאוביקט תאריך-שעה ייכתב בתור long בצירוף אזור זמן אמור להשפיע רק על שתי שורות במערכת, כי כל הקוד שקורא את שדה התאריך עובר דרך אותה שורה.

ToCode
1 420
# קוד מושלם אם הייתי יודע איך יראו כל הדרישות העתידיות מהמערכת הייתי שמח לכתוב את הקוד המושלם. בעולם האמיתי אני מעדיף להתמקד בקוד שקל לשנות אותו.

ToCode
1 420
# יש לי שלושה ימים עד הראיון עבודה בריאקט - מה ללמוד? כשהשאלה מהכותרת נשאלה ברדיט ידעתי שזה הולך להיות מעניין. אלה הטיפים המרכזיים שמצאתי שם: 1. כולם מתעסקים עם ניהול סטייט - וצריך להגיד, הסיפור של ניהול סטייט מלווה אותנו מאז שריאקט נוצרה ויישאר איתנו כל עוד לא יהיה שינוי ארכיטקטוני מאוד משמעותי בספריה. 2. הרבה אנשים מדברים על ביצועים ועל הוקים כמו useCallback, אבל פחות ממה שחשבתי. כמעט אף אחד לא מתייחס ל Concurrent Mode ול useTransition 3. אקוסיסטם הוזכר בתור טיפ אבל לא נראה שקיבל מספיק דגש. זה הגיוני כי האקוסיסטם של ריאקט עצום, אם במקרה יש לכם ניסיון עם רידאקס ואתם מתראיינים במקום שמשתמש ברידאקס זה אחלה. אבל אם המקום משתמש בזוסטנד אז השיחה תהיה משעממת. אותו דבר עם ספריות לתקשורת ואפילו עם next.js. בסוף כשמראיינים מפתחים למשרות ריאקט הדגש הוא על הליבה של ריאקט, ופחות על המסביב. 4. הרבה אנשים כן דיברו על החשיבות של פיתוח Front End באופן כללי - אם זה טייפסקריפט, היכרות טובה עם JavaScript ויכולות חדשות של השפה, ואפילו CSS ויכולות חדשות שלו. אבל הכי חשוב לשים לב לתחילת השאלה - "אני מפתח עם שלוש שנות ניסיון בריאקט". זה בסדר גמור לעבוד שלוש שנים עם כלי בלי להבין את כל הניואנסינים שלו ובלי להשתמש בכל היכולות. חשוב וטוב לקחת מדי פעם את הזמן כדי לחזק את הידע. כותב השאלה הקציב לזה שלושה ימים והטריגר היה ראיון עבודה. אנחנו לא צריכים לחכות שלוש שנים, ולא חייבים טריגר חיצוני.

ToCode
1 420
# שלושה פיצ'רים מלהיבים במיוחד בפייתון 3.12 פייתון 3.12 יצאה לא מזמן והביאה איתה מספר שיפורים שיכולים להשפיע כמעט על כל אחד ואחת מאיתנו. אלה ה-3 שאני הכי אהבתי. ## תחביר קל יותר לפונקציות גנריות עד 3.12 בשביל לכתוב פונקציות גנריות היה צריך להגדיר משתנים מסוג TypeVar, לאתחל אותם ולתת להם שמות לפני שאפשר היה להגיע לכתוב את הפונקציה. זה למשל קוד גנרי מגירסאות פייתון ישנות:
from typing import TypeVar

StringOrNumber = TypeVar('StringOrNumber', str, int)

def add(x: StringOrNumber, y: StringOrNumber) -> StringOrNumber:
  return x + y
גירסה 3.12 הוסיפה תמיכה ב PEP 695 שאומר שאנחנו יכולים להגדיר פונקציות גנריות כמו בסקאלה כלומר:
def max[T](args: Iterable[T]) -> T:
    ...
הבעיה היחידה היא שעדיין אי אפשר לשחק עם הפיצ'ר כי גם ב mypy וגם ב PyCharm עדיין מפתחים את התמיכה, אבל לפחות יש למה לצפות. ## קינון של מחרוזות f הפצ'ר הזה כבר עובד ופותר בעיה מאוד מעצבנת עם מחרוזות f:
songs = ['Take me back to Eden', 'Alkaline', 'Ascensionism']
print(f"This is the playlist: {", ".join(songs)}")
וכן ראיתם נכון - בקוד הפייתון שבתוך הסוגריים המסולסלים מחרוזת כתבתי מרכאות ופייתון לא נלחץ. ## הגדרת טיפוס ל kwargs עם TypedDict פיצ'ר מלהיב אחרון הוא היכולת להגדיר במדויק איזה פרמטרים אנחנו רוצים לקבל לתוך מילון בפונקציה שמקבלת אוסף משתנה של ארגומנטים עם TypedDict:
from typing import TypedDict, Unpack

class Movie(TypedDict):
  name: str
  year: int

def foo(**kwargs: Unpack[Movie]): ...
זאת יכולת שהיתה חזרה הרבה זמן וכמעקף הרבה פעמים ויתרתי על לקבל **kwargs לפונקציה והעברתי ממש מילון. יכולת זו כבר עובדת ב mypy. ממה שהבנתי ב PyCharm זה עדיין בפיתוח. רשימת השינויים המלאה של 3.12 נמצאת כאן: https://docs.python.org/3/whatsnew/3.12.html לכו להסתכל וספרו בתגובות איזה פיצ'רים אתם הכי אהבתם.