(נושא בסיסי – למרות מספר מורכבויות, המופיע בקורס פייתון למתחילים)
חלק א:
מודולים – שיטה לחלק את הקוד
מודולים קיימים בכל שפות התכנות, מפני שהם מציעים את האפשרות הבסיסית לכתוב תוכנית מחשב גדולה. בקורסי bootcamp מתרגלים עם התלמידים כתיבה בקבוצות של תוכנית אחת, כאשר כל חבר בצוות כותב חלק מהתוכנית, בתוך מודול נפרד.
כמעט בכל שפת תכנות:
מודול אחד מתאים (פחות או יותר)לקובץ אחד של מערכת ההפעלה.
גם בפייתון זה המצב, וקובץ יחיד (עם הסיומת py) הוא מודול.
import
כדי להשתמש במודל מתוך מודול אחר (או ישירות מתוך ה – interpreter), משתמשים בפקודת פייתון בשם import.
כדי להדגים זאת ניצור קובץ פייתון עם הקוד הבא:
print('I am module 1.')
הקוד נראה מאד בסיסי.. ואולי גם מבלבל (לא ברור איזה קוד אפשר לייבא כאן) אבל הוא ישמש אותנו כדי להיזכר בשתי העובדות הבאות:
- פייתון היא שפה דינאמית, ובה הכל קורה בזמן ריצה.
- כאשר מייבאים מודול באמצעות import, בעצם מריצים אותו !!!
מייד נדגים זאת באמצעות ייבוא (import) ישיר של המודול ל – interpreter:
מודגם כאן על Linux, אבל יפעל באותה הצורה גם במערכות הפעלה אחרות)
yuval> ls -l
total 4
-rw-rw-r-- 1 yuval yuval 23 Oct 5 11:51 mod_1.py
yuval>
yuval> python3
Python 3.8.5 (default, Sep 9 2020, 11:29:34)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import mod_1
I am module 1.
>>>
ואכן רואים שהמודול הופעל, ושורת ה-print התבצעה.
לאחר ההפעלה השם mod_1 (שמו של המודול שנטען) מוכרת ע"י ה- interpreter.
נשים לב גם כי אין אפשרות לטעון את המודול שוב:
>>> mod_1
<module 'mod_1' from '/home/yuval/Documents/languages/python/progs/learnpython/learn/unit6-modules/mod_1.py'>
>>> type(mod_1)
<class 'module'>
>>>
>>> import mod_1
>>>
איך קוד מיובא מהמודול
שורת ה – print שראינו קודם אינה שימושית ביותר, והיא מתבצעת רק פעם אחת (כאשר מייבאים את המודול. ראינו שאם מנסים לייבא את המודול שוב, השורה לא מתבצעת שוב.
לעומת זאת, פקודות שיוצרות שמות (של משתנים או פונקציות) ייתבצעו גם הם רק פעם אחת, אבל אז ישאירו מאחוריהם את השמות, ובאל אפשר יהיה להשתמש.
את הקוד הבא שמרתי בתוך קובץ בשם mod_2.py :
my_num=5
def my_func():
print('Function mod2_f from module mod_2')
השימוש במודול mod_2:
>>> import mod_2
>>> mod_2.my_num
5
>>> mod_2.my_func()
Function mod2_f from module mod_2
>>>
מרחבי שמות
עפ"י הדוגמה, השמות שהוגדרו ע"י המודול מופיעים כתכונות של אובייקט המודול. כדי לפנות אליהם צריך להשתמש בנקודה.
בדרך כלל מדובר במשהו חיובי ומומלץ, מפני שכך נקבל הגנה מפני תופעה חמורה של התנגשות שמות.
אם למשל הגדרתי משתנה בשם my_num, ולאחר מכן ביצעתי את ה – import, הכל בסדר:
המשתנה my_num שונה מאשר המשתנה mod_2.my_num, ושניהם קיימים.
from..import
אפשר לייבא שם ממודול ישירות אל טבלת הסמלים המקומית.
הנה mod_3.py :
HUNDRED = 100
def show_num(num=None):
if num is not None:
print(num)
else:
print(HUNDRED)
הפעם לא נטען את המודול כולו, אלא רק את הפונקציה show_num:
>>> from mod_3 import show_num
>>>
>>> show_num(15)
15
>>>
נשים לב מה ייבאנו ומה לא:
>>>
>>> mod_3.HUNDRED
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'mod_3' is not defined
>>> mod_3.show_num
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'mod_3' is not defined
>>>
>>> mod_3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'mod_3' is not defined
>>>
>>> show_num
<function show_num at 0x7f568e528550>
>>>
כלומר:
לא יובא השם mod_3, וכמובן שמתחתיו לא יובאו הפונקציה או המשתנה.
אבל…
הפונקציה show_num יובאה ישירות את טבלת הסמלים הנוכחית.
האם היא מסוגלת תפעול באורח תקין?
האם היא "זוכרת" את המשתנה HUNDRED למרות שלנו אין גישה אליו?
>>>
>>> show_num()
100
>>>
אנו רואים כי הפונקציה "זוכרת" את סביבתה המקורית.
(המשך בחלק השני: מודולים בפייתון – חלק ב)