הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

טיפ פנדס: איך להתעלם מטעויות Encoding בקובץ

11/09/2020

הפקודה read_csv של פנדס היא מופלאה. רוב קבצי ה CSV שאנחנו מוצאים בדוגמאות באינטרנט כתובים בקידוד UTF8 וזה בדיוק גם קידוד ברירת המחדל של read_csv.

אבל כשעוברים ממשחקים לעולם האמיתי אנחנו מוצאים קבצי CSV פחות נחמדים: החל מקבצים ישנים שמקודדים ב Extended ASCII או במקרה העוד יותר גרוע קבצים שמערבבים תווים בכל מיני קידודים.

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

פנדס ממש לא אהב את זה וכשניסיתי לטעון את המאגר לפנדס קיבלתי את ההודעה הבאה:

>> pd.read_csv('053cea08-09bc-40ec-8f7a-156f0677aff3.csv', '|')

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xee in position 0: invalid continuation byte

עד לפה לא מבהיל מדי כי תמיד אפשר להעביר Encoding לפנדס. אבל הפעם גם זה לא עבד:

>> pd.read_csv('053cea08-09bc-40ec-8f7a-156f0677aff3.csv', encoding='iso8859-8')

UnicodeDecodeError: 'charmap' codec can't decode byte 0xd2 in position 127430: character maps to <undefined>

מה עושים? תשמחו לשמוע שיש פיתרון יחסית פשוט: נפתח את הקובץ עם הקידוד שאנחנו רוצים ונבקש מ open שתחליף תווים שלא תואמים לקידוד בסימני שאלה. את ה File Handle נעביר לפנדס שישמח לקבל את המידע אחרי פיענוח. הקוד כולו נראה כך:

>> fd = open('053cea08-09bc-40ec-8f7a-156f0677aff3.csv', encoding='iso8859-8', errors='replace')
>> df = pd.read_csv(fd, '|')

עכשיו אפשר להינות מהמידע שהצלחנו לקרוא למשל מי יצרנית הרכב הפופולרית בישראל:

df.groupby('tozeret_nm').size().sort_values(ascending=False)

tozeret_nm
מזדה יפן         299175
יונדאי קוריאה    228002
קיה קוריאה       205592
טויוטה יפן       189340
סקודה צ'כיה      173473

לדעת ריאקט בלי רידאקס

10/09/2020

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

אבל-

הרבה אנשי ריאקט מהתעשיה ישאלו אותך על רידאקס בראיונות, ויעדיפו לגייס מתכנת שמדבר בשפה שלהם. הרבה אנשי פייתון מהתעשיה עובדים ב Pandas מהיום הראשון שלהם עם פייתון, ויתקשו להאמין שאת יודעת פייתון אם את לא יודעת מה זה DataFrame. או שהם יחשבו שאת לא מתכנתת פייתון מהסוג שהם מחפשים. והרבה אנשי CSS מהתעשיה יופתעו מאוד כשתגיעי לראיון בלי לדעת איך להשתמש ב flexbox וב grid.

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

המספר בקפה

09/09/2020

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


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

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

ובכל פעם, האתגר הסודי שלי היה לקוות שאקבל את אחד המספרים האהובים עליי: 7 או 22.

ולמה זה אתגר?

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

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

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

בקפה הם אף פעם לא אמרו לי לא.

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

הדרך הטובה ביותר לקבל את מה שאתם רוצים היא פשוט לבקש.

זה לא קל כמו שזה נראה ; זה דורש תרגול.

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

מי נתן לך את זה ב 35 ?

08/09/2020

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

אם קניתי קילו מלפפונים ב 10 ש"ח, וחודש אחרי אני מגיע לחנות ואני רואה שהמחיר הוא 20, אני אחשוב פעמיים לפני שאקנה (למרות שאולי אם כבר בביקור הראשון המחיר היה 20 ש"ח הייתי קונה בשמחה).

אם קניתי מחשב באלפיים ש"ח והייתי מרוצה ממנו, הסיכוי שאוציא 10,000 ש"ח על מחשב הוא מאוד נמוך. אני אחפש משהו דומה לדבר שקניתי קודם (אפילו שעברו 5 שנים מאז שקניתי את המחשב הקודם).

ובגלל ומוצרים עולים אחרת אז לכל קניה אני מוסיף סיפור מסוים - למשל כשקניתי פעם ראשונה שזיפים ב 25 ש"ח לקילו (!!!) אז אמרתי לעצמי "טוב בטח אלה שזיפים ממש מעולים במחיר הזה". וגם ההיפך אם קניתי עגבניות ב 4 ש"ח לקילו יכולתי לספר לעצמי שמצאתי אחלה דיל ושווה להתאמץ לחפש פירות וירקות זולים כי בסוף מוצאים.

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

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

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

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

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

עזבו אדומות, בואו נגלה מי הערים הירוקות בעזרת פייתון

07/09/2020

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

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

https://www.gov.il/he/Departments/DynamicCollectors/cities-ramzor

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

https://www.gov.il/he/api/DataGovProxy/GetDGResults

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

המשך קריאה

איך לקרוא קובץ CSV למערך של מפות ב Clojure

06/09/2020

בתיעוד על ספריית העבודה עם CSV של Clojure מצאתי את קטע הקוד הבא, שהופך קובץ CSV למערך של מפות:

(defn csv-data->maps [csv-data]
  (map zipmap
       (->> (first csv-data)
            repeat)
      (rest csv-data)))

הקטע משתמש במספר קסמים של Clojure ומשקף הרבה מהדברים היפים בשפה. בואו נפרק אותו כדי להבין איך זה עובד.

המשך קריאה

פייתון, פסיק ושגיאות לא הגיוניות

05/09/2020

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

def first_letter(text):
    return text[0]

text = "I can see a mountain",
print(first_letter(text))

הצלחתם לנחש מה הקוד מדפיס? נריץ ונבדוק אם צדקנו:

$ python3 ouch.py 
I can see a mountain

את כל הטקסט??? פייתון...

הבעיה היא כמובן הפסיק בסוף שורת ההשמה:

text = "I can see a mountain",

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

וזאת אולי הסיבה המרכזית שכדאי להוסיף Type Hints לקוד שלכם. הכתיב הבא:

def first_letter(text: str):
    return text[0]

text = "I can see a mountain",
print(first_letter(text))

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

$ python3 -m mypy ouch.py
ouch.py:5: error: Argument 1 to "first_letter" has incompatible type "Tuple[str]"; expected "str"
Found 1 error in 1 file (checked 1 source file)

(מאיפה לומדים על Type Hints אתם שואלים? נו, תשמחו לשמוע שכבר בניתי קורס וידאו בדיוק על זה ועל עוד המון פיצ'רים מדליקים של פייתון שיחסכו לכם זמן בפיתוח קוד בעולם האמיתי. הוא נקרא פייתון מתקדם וכולל אינספור טיפים לפיתוח פייתון לאנשים שכבר יודעים את הבסיס).

להתאמן בבית

04/09/2020

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

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

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

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

מבחינת כלי פיתוח גיטהאב וגיטלאב מספקים מנגנוני CI/CD חינמיים לגמרי כך שאפשר לבנות Pipeline לתוכנה שבניתם בבית שיהיה טוב כמו ה Pipelines שתמצאו בתעשיה.

מבחינת Data יש לגוגל מנוע חיפוש על Data Sets עם מעל 25 מיליון סטים של מידע מכל הסוגים כדי שתוכלו לנתח מידע או לבנות אלגוריתמים כמו שהיו עושים בחברות גדולות. אתם כבר לא צריכים לעבוד בחברה גדולה בשביל להתאמן על ניתוח כמויות כאלה של מידע.

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

תתחילו בלחפש את השאלות

03/09/2020

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

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

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

יוטיוב מלא במדריכי "איך לבנות אפליקציית React ו Node.JS מאפס", "איך לכתוב פאקמן ב Python" או "איך להתקין ולהגדיר את ה vimrc המושלם". כשאתם חדשים לגמרי לנושא אלה בדיוק סוג המדריכים שתרצו לצפות בהם. אני מוצא שכמעט תמיד ברגע שאני מצליח לכתוב תוכניות פשוטות אני אלמד הרבה יותר טוב אם אשבור את הראש על שאלות מעניינות או אחפש בעצמי את הסטאפ המושלם.

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

כלי טוב מדי

02/09/2020

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

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

וזאת בדיוק הסיבה ללמוד להשתמש ב cut.

או ניקח דוגמא משפות תכנות: כל מה שאפשר לכתוב עם map אפשר לכתוב עם לולאת for. ועדיין אם יש לי רשימה של מספרים ואני רוצה לחשב את סכום הריבועים שלהם אני אעדיף לכתוב:

const numbers = [1, 2, 3, 4];
const plus = (a, b) => a + b;
const square = x => x * x;
const result = numbers.map(square).reduce(plus);
console.log(result);

על פני:

const numbers = [1, 2, 3, 4];
let result = 0;

for (let i=0; i < numbers.length; i++) {
  result += numbers[i] * numbers[i];
}

console.log(result);

ובדיוק מהסיבה הזאת אני מעדיף את const על פני let.

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

הכלי הטוב מדי מביא איתו יותר עומס ומסתיר את הדבר שבאמת רצינו לעשות.