2.19. كتابة الوحدات¶
أي ملف .py هو وحدة. تقسيم برنامج نصي متنامٍ عبر بضعة ملفات يبقي كل ملف قصيرًا ويتيح مشاركة الدوال المساعدة المشتركة بين البرامج النصية.
2.19.1. تقسيم برنامج نصي¶
اسحب مجموعة من الدوال المترابطة إلى ملفها الخاص:
camera_utils.py
def banner():
print("OpenMV")
def label(text):
return "[" + text + "]"
main.py
import camera_utils
camera_utils.banner()
print(camera_utils.label("ready"))
المخرجات:
OpenMV
[ready]
يقع الملفان جنبًا إلى جنب في الدليل نفسه. عندما يعمل main.py، يقرأ import camera_utils ملف camera_utils.py مرة واحدة، وينفّذ عباراته عالية المستوى، ويربط كائن الوحدة الناتج بالاسم camera_utils في main. أي import camera_utils ثانٍ من أي مكان آخر يُرجع الكائن نفسه -- إذ تُخزَّن الوحدات في الذاكرة المؤقتة بعد تحميلها الأول.
يأتي اسم الوحدة من اسم ملفها، لذا يُستورد camera_utils.py كـ import camera_utils.
2.19.2. الوحدات متعددة الملفات (الحزم)¶
يمكن أن تكون الوحدة أيضًا دليلًا من الملفات بدلًا من ملف .py واحد. يصبح اسم الدليل اسم الوحدة، وتكون الملفات بداخله وحداتها الفرعية:
camera_utils/
__init__.py
text.py
timing.py
__init__.py هو الملف الذي يعمل عند استيراد الحزمة نفسها؛ ويمكن أن يكون فارغًا، أو يمكنه إعادة تصدير أسماء مختارة من الوحدات الفرعية. ويتم الوصول إلى الوحدات الفرعية باسم منقّط:
import camera_utils.text
from camera_utils.timing import elapsed
camera_utils.text.label("ready")
داخل الحزمة، يمكن للوحدات الفرعية الوصول إلى بعضها إما بالاسم المنقّط الكامل أو عبر استيراد نسبي يستخدم نقطة بادئة لتعني "هذه الحزمة":
camera_utils/timing.py
from . import text # the sibling submodule
def stamp(value):
return text.label(str(value))
ولجلب اسم محدد بدلًا من ذلك، سمّه بعد الشقيق المنقّط:
from .text import label
def stamp(value):
return label(str(value))
تبقي الاستيرادات النسبية الحزمة مكتفية ذاتيًا: إعادة تسمية دليل الحزمة لا تتطلب تحرير كل وحدة فرعية.
استخدم حزمة عندما ينمو ملف واحد متجاوزًا حجمًا مريحًا، أو عندما تنتمي مجموعة من الوحدات المترابطة معًا تحت فضاء أسماء واحد. وللبرامج النصية اليومية، يكفي ملف .py واحد.
2.19.3. حارس __name__¶
لكل وحدة اسم مدمج __name__. وقيمته تعتمد على كيفية استخدام الملف:
عندما يُشغّل الملف مباشرةً، يُضبط
__name__على السلسلة النصية"__main__".عندما يُستورد الملف بواسطة برنامج نصي آخر، يُضبط
__name__على اسم الوحدة -- اسم الملف دون.py.
الصيغة الاصطلاحية التي تستخدم هذا هي:
label_util.py
def label(text):
return "[" + text + "]"
if __name__ == "__main__":
print(label("self-test"))
المخرجات (عند التشغيل المباشر):
[self-test]
عندما يُستورد الملف نفسه بدلًا من ذلك، يُضبط __name__ على اسم الوحدة، فتُتخطى كتلة if ولا يعمل أي شيء إضافي:
>>> import label_util
>>> label_util.__name__
'label_util'
استخدم هذا النمط لإرفاق اختبار سريع أو عرض توضيحي بملف مكتبة دون إزعاج البرامج النصية التي تستورده.