إنشاء Module وPackage في Python والاستيراد بين الملفات | أساسيات بايثون 24

إنشاء Module وPackage في Python والاستيراد بين ملفات المشروع

إذا أصبح ملف Python واحدًا طويلًا ومزدحمًا، فالخطوة التالية ليست البحث عن مكتبة جديدة، بل تقسيم الكود إلى Modules محلية تستطيع استيرادها بين ملفات مشروعك.

في هذا الدرس من أساسيات بايثون سنركز على جانب مختلف عن شرح صيغ import العامة: ستنشئ ملفًا مثل helpers.py، تستورده من main.py، ثم تنتقل إلى Package يحتوي عدة Modules، وتفهم دور __init__.py والاستيراد النسبي، وأشهر أسباب فشل الاستيراد بين ملفات المشروع.

إذا كنت تريد أولًا تعلم import math و from ... import و as بالتفصيل، فابدأ من دليل شرح import في Python للمبتدئين.

{alertInfo} الفكرة الأساسية هنا: ملف .py يمكن أن يكون Module قابلًا لإعادة الاستخدام، ومجلد يحتوي Modules مترابطة يمكن تنظيمه كـ Package.

{getToc} $title={محتوى المقال}

شرح فكرة Module في Python وكيف تنقل الدوال إلى ملف مستقل وتستوردها في ملف آخر

ما الفرق بين Module وPackage في Python؟

الـ Module هو ملف Python واحد، مثل helpers.py أو calculator.py. أما الـ Package فهو مجلد يجمع Modules مرتبطة ببعضها داخل مساحة أسماء واحدة.

العنصر شكله متى تستخدمه؟
Module helpers.py عندما تريد نقل دوال أو متغيرات مترابطة إلى ملف مستقل.
Package tools/ عندما يصبح لديك أكثر من Module مرتبطة وتريد تنظيمها داخل مجلد.

إنشاء Module محلي: ملف helpers.py

ابدأ بأبسط حالة: ملفان داخل المجلد نفسه. أنشئ مجلد مشروع يحتوي:

my_project/
├── main.py
└── helpers.py

داخل helpers.py ضع دوال تريد إعادة استخدامها:

def format_name(name):
    return name.strip().title()


def is_valid_age(age):
    return age >= 0

الآن أصبح helpers.py Module محليًا يحتوي منطقًا يمكن استخدامه من ملفات أخرى بدل تكراره.

استيراد ملف Python من ملف آخر في نفس المجلد

داخل main.py يمكنك استيراد الملف كاملًا بدون كتابة الامتداد .py:

import helpers

name = helpers.format_name("  ali saleh  ")
print(name)

الناتج:

Ali Saleh

ويمكنك استيراد دالة محددة فقط:

from helpers import format_name

print(format_name("  sara ahmed "))
{alertSuccess} عند استيراد ملف محلي من المجلد نفسه، اكتب اسم الملف بدون .py: استخدم import helpers وليس import helpers.py.

مراجعة سريعة: import وfrom import وas

هذه الصفحة لا تعيد شرح صيغ import من البداية، لكنك ستراها أثناء تنظيم الملفات المحلية:

الصيغة مثال محلي النتيجة
import module import helpers تستخدم helpers.function().
from module import name from helpers import format_name تستخدم الدالة مباشرة.
import module as alias import helpers as h اسم محلي أقصر عند الحاجة.
مثال استخدام مكتبة math و random في بايثون للمبتدئين مع أوامر import

للتفصيل في المكتبات الجاهزة مثل math وrandom وصيغ الاستيراد المختلفة، استخدم دليل import المرجعي بدل توسيع هذا الدرس في نفس النية.

مقارنة بين import و from import و import as في Python مع أمثلة مبسطة للمبتدئين

متى أنقل الكود إلى Module مستقل؟

لا تقسّم المشروع إلى ملفات كثيرة لمجرد التقسيم. أنشئ Module عندما يصبح لديك جزء من الكود له مسؤولية واضحة ويمكن إعادة استخدامه.

  • helpers.py لدوال مساعدة عامة.
  • validation.py للتحقق من المدخلات.
  • reports.py لإنشاء التقارير.
  • storage.py للقراءة والكتابة المرتبطة بالبيانات.

إذا كان هدفك هو تعلم هيكل المشروع كاملًا مثل README وrequirements.txt وتقسيم المجلدات على مستوى أوسع، راجع مقال تنظيم ملفات مشروع Python بعد الأساسيات.

إنشاء Package في Python

عندما تزيد Modules المرتبطة ببعضها، يمكن جمعها داخل Package. مثال:

my_project/
├── main.py
└── tools/
    ├── __init__.py
    ├── text.py
    └── numbers.py

في هذا المثال، المجلد tools هو Package، والملفان text.py وnumbers.py هما Modules داخله.

داخل tools/text.py:

def clean_text(text):
    return text.strip().lower()

وفي main.py:

from tools.text import clean_text

value = clean_text("  PYTHON  ")
print(value)

الناتج:

python

ما وظيفة __init__.py؟

للمبتدئ، أفضل طريقة لإنشاء Package عادية وواضحة هي وضع ملف باسم __init__.py داخل المجلد. يمكن أن يكون الملف فارغًا تمامًا.

tools/
├── __init__.py
├── text.py
└── numbers.py

وجود __init__.py يجعل نية المجلد واضحة كـPackage عادية، ويمكن أيضًا وضع كود تهيئة أو إعادة تصدير أسماء داخله عند الحاجة. في Python الحديثة توجد أيضًا namespace packages قد تعمل بدون هذا الملف، لكنها حالة أكثر تقدمًا ولا نحتاجها هنا.

مثلًا، يمكن أن يحتوي tools/__init__.py على:

from .text import clean_text

ثم يصبح الاستيراد من خارج الحزمة:

from tools import clean_text

print(clean_text("  Report  "))

الاستيراد النسبي Relative Import داخل Package

إذا كان Module داخل Package يحتاج Module آخر من الحزمة نفسها، يمكن استخدام نقطة في بداية المسار.

لنفترض أن لدينا:

tools/
├── __init__.py
├── text.py
└── reports.py

داخل tools/reports.py يمكن استيراد clean_text من الملف المجاور:

from .text import clean_text


def build_title(title):
    return clean_text(title).title()

النقطة . تعني: ابدأ من الـPackage الحالية. أما .. فتعني الرجوع إلى الـPackage الأب.

{alertWarning} الاستيراد النسبي يعتمد على سياق الـPackage. إذا شغّلت ملفًا داخليًا مباشرة مثل python tools/reports.py فقد يظهر ImportError: attempted relative import with no known parent package. شغّل نقطة الدخول من جذر المشروع أو شغّل الـModule باستخدام python -m عند الحاجة.

مثال: تشغيل Module داخل Package باستخدام -m

إذا كان لديك هذا الهيكل:

my_project/
└── tools/
    ├── __init__.py
    ├── text.py
    └── reports.py

ومن داخل reports.py تستخدم relative import، انتقل في Terminal إلى my_project ثم شغّل:

python -m tools.reports

بهذه الطريقة تعرف Python أن reports جزء من Package اسمها tools.

ماذا عن if __name__ == "__main__"؟

هذه العبارة مفيدة عندما يحتوي Module على دوال قابلة للاستيراد، لكن لديك أيضًا كود تريد تشغيله فقط عند تنفيذ الملف مباشرة.

def greet(name):
    return f"Hello {name}"


if __name__ == "__main__":
    print(greet("Ali"))

عند استيراد الملف، يتم تعريف greet() لكن الكود داخل الشرط لا يعمل تلقائيًا. ولأن هذا الموضوع له نية مستقلة وشرح أعمق، راجع مقال ما معنى if __name__ == "__main__" في Python؟.

لماذا يظهر ModuleNotFoundError مع ملف محلي؟

ملخص أخطاء import الشائعة في بايثون مثل ModuleNotFoundError و ImportError وكيف تتجنبها

إذا كان الاستيراد لملف من مشروعك، فلا تبدأ مباشرة بـpip install. افحص أولًا مكان الملف وطريقة تشغيل المشروع.

المشكلة مثال ما الذي تراجعه؟
الملف غير موجود في المسار المتوقع import helpers تأكد أن helpers.py موجود في مكان يمكن لبايثون الوصول إليه.
تشغيل ملف داخلي من مجلد فرعي python tools/reports.py شغّل من جذر المشروع أو استخدم python -m tools.reports.
اسم ملف يتعارض مع مكتبة random.py غيّر اسم الملف ولا تستخدم أسماء المكتبات القياسية لملفات مشروعك.
relative import خارج سياق Package from .text import clean_text لا تشغّل Module الداخلية مباشرة كنقطة دخول مستقلة.
المشكلة في مكتبة خارجية import requests هنا افحص التثبيت والبيئة باستخدام دليل الخطأ المتخصص.

إذا كانت المشكلة مع مكتبة خارجية أو بيئة Python نفسها، راجع حل خطأ ModuleNotFoundError: No module named.

هل أستخدم sys.path.append لحل مشكلة الاستيراد؟

يمكن تعديل sys.path يدويًا، لكن لا تجعله الحل الأول في مشروع مبتدئ. في معظم الحالات الأفضل أن تنظّم Modules داخل مشروع واضح، وتشغّل البرنامج من جذر المشروع، وتستخدم imports مناسبة للـPackage.

إضافة مسارات يدويًا قد تخفي مشكلة في بنية المشروع وتجعل تشغيل الكود يعتمد على مسارات خاصة بجهاز واحد.

مثال كامل: من ملف واحد إلى Package صغيرة

لنفترض أن مشروعك بدأ بملف واحد ثم أصبح لديك منطق للنصوص والأرقام. الهيكل:

my_project/
├── main.py
└── tools/
    ├── __init__.py
    ├── text.py
    └── numbers.py

داخل tools/text.py:

def normalize_name(name):
    return name.strip().title()

داخل tools/numbers.py:

def is_positive(number):
    return number > 0

داخل main.py:

from tools.text import normalize_name
from tools.numbers import is_positive

name = normalize_name("  ahmed ali ")
score = 25

print(name)
print(is_positive(score))

الناتج:

Ahmed Ali
True

الآن كل ملف له مسؤولية واضحة، وmain.py أصبح نقطة تشغيل تجمع الأدوات بدل احتواء كل التفاصيل.

أفضل ممارسات Modules وPackages للمبتدئ

  • ابدأ بملفات قليلة، ولا تقسّم المشروع أكثر من حاجته.
  • اختر أسماء ملفات تصف مسؤوليتها مثل validation.py بدل file2.py.
  • لا تسمِّ ملفاتك random.py أو json.py أو datetime.py إذا كنت تحتاج المكتبات الأصلية نفسها.
  • شغّل المشروع من مجلده الجذر عندما تبدأ باستخدام Packages.
  • استخدم absolute imports بين نقطة الدخول والحزم عندما يكون ذلك أوضح.
  • استخدم relative imports داخل الحزمة عندما تكون العلاقة داخلية وواضحة.
  • لا تستخدم sys.path.append() كحل تلقائي لكل خطأ استيراد.

أسئلة شائعة

هل أي ملف .py يعتبر Module في Python؟

نعم، ملف Python يمكن استيراده كـModule عندما يكون موجودًا في مسار يستطيع نظام الاستيراد الوصول إليه.

كيف أستورد ملف Python من ملف آخر في نفس المجلد؟

إذا كان لديك helpers.py بجانب main.py، استخدم import helpers أو from helpers import function_name بدون كتابة .py.

ما الفرق بين Module وPackage؟

Module هو ملف Python واحد. Package تجمع Modules داخل مجلد ويمكن الوصول إلى Modules داخلها باستخدام أسماء منقطة مثل tools.text.

هل __init__.py إلزامي دائمًا؟

ليس في كل الحالات الحديثة بسبب namespace packages، لكن إضافته هي الطريقة الأبسط والأوضح للمبتدئ لإنشاء Package عادية، ويمكن أن يبقى فارغًا.

لماذا يفشل relative import عندما أشغل الملف مباشرة؟

لأن relative import يعتمد على معرفة الـPackage التي ينتمي إليها الملف. عند تشغيل Module داخلية مباشرة قد تفقد هذا السياق؛ شغّل نقطة الدخول من جذر المشروع أو استخدم python -m package.module.

مصادر رسمية للتوسع

الخلاصة

بعد فهم أساسيات import، الخطوة العملية هي استخدامه لتنظيم كودك أنت. أنشئ Module مثل helpers.py عندما تريد إعادة استخدام مجموعة دوال، ثم اجمع Modules المرتبطة داخل Package مثل tools عندما يكبر المشروع.

ركز أولًا على الاستيراد بين ملفات المشروع، وافهم __init__.py وrelative imports ومكان تشغيل البرنامج. بهذه الطريقة تتجنب كثيرًا من مشاكل ModuleNotFoundError وتنتقل من ملف واحد مزدحم إلى مشروع أوضح وأسهل في التطوير.

{alertSuccess} القاعدة العملية: ابدأ بـModule عندما تحتاج ملفًا مستقلًا لمسؤولية واضحة، وانتقل إلى Package عندما يصبح لديك عدة Modules مرتبطة ببعضها.

إرسال تعليق

أحدث أقدم