الفصل الثالث عشر: تنظيم المشاريع – الوحدات (Modules) والحزم (Packages)
مقدمة الفصل
عندما تعمل على مشاريع صغيرة، قد يكون من المقبول كتابة كل الكود في ملف واحد. لكن مع نمو المشروع وزيادة تعقيده، يصبح هذا الأسلوب كابوسًا. سيصعب عليك العثور على أجزاء معينة من الكود، وستزداد احتمالية حدوث أخطاء، وستكون عملية الصيانة والتطوير شبه مستحيلة.
لهذا السبب، يستخدم المبرمجون المحترفون تقنيات لتنظيم مشاريعهم وتقسيمها إلى أجزاء أصغر وأكثر قابلية للإدارة. في هذا الفصل، سنتعلم أهم طريقتين لتنظيم الكود في بايثون:
- الوحدات (Modules): لتقسيم الكود إلى ملفات منفصلة.
- الحزم (Packages): لتجميع الوحدات المترابطة معًا في مجلدات.
1. ما هي الوحدة (Module)؟
في أبسط صورها، الوحدة هي أي ملف بايثون بامتداد .py
. عندما تقوم بإنشاء دالة أو كلاس في ملف، يمكنك “استيراد” هذه الوحدة في ملف آخر واستخدام ما بداخلها. هذا يسمح لك بتقسيم منطق برنامجك إلى ملفات متعددة، كل ملف مسؤول عن مهمة محددة.
كيفية إنشاء واستخدام وحدة
الخطوة الأولى: إنشاء الوحدة لنفترض أننا نعمل على برنامج يتطلب عمليات حسابية متكررة. بدلاً من كتابة هذه الدوال في ملفنا الرئيسي، سنقوم بإنشاء وحدة خاصة بها.
أنشئ ملفًا جديدًا باسم math_operations.py
واكتب بداخله الكود التالي:
# This is our module: math_operations.py
def add(x, y):
"""This function adds two numbers."""
return x + y
def subtract(x, y):
"""This function subtracts two numbers."""
return x - y
شرح هذه الجزئية:
لقد أنشأنا الآن وحدة اسمها math_operations
. تحتوي على دالتين بسيطتين. لاحظ أننا أضفنا نصًا توضيحيًا (docstring) داخل كل دالة، وهي ممارسة جيدة لتوثيق الكود.
الخطوة الثانية: استيراد الوحدة في ملف آخر
الآن، أنشئ ملفًا آخر في نفس المجلد باسم main.py
. هذا سيكون برنامجنا الرئيسي. لاستخدام الدوال التي أنشأناها، سنقوم باستيراد الوحدة math_operations
.
# This is our main program: main.py
# We import the entire module
import math_operations
# Now we can use the functions from the module
# We must prefix them with the module name and a dot
result1 = math_operations.add(10, 5)
result2 = math_operations.subtract(10, 5)
print(f"Addition result: {result1}")
print(f"Subtraction result: {result2}")
شرح هذه الجزئية:
import math_operations
: هذا السطر يخبر بايثون بأننا نريد استخدام الكود الموجود في ملفmath_operations.py
.math_operations.add(...)
: للوصول إلى دالة داخل وحدة مستوردة، نكتب اسم الوحدة، متبوعًا بنقطة (.
)، ثم اسم الدالة. هذا يمنع تضارب الأسماء إذا كانت لديك دالة بنفس الاسم في ملفك الرئيسي.
طرق أخرى للاستيراد
في بعض الأحيان، قد ترغب في استيراد دالة معينة فقط، أو إعطاء الوحدة اسمًا مختصرًا.
استيراد دالة محددة باستخدام from
:
# Import only the 'add' function from the module
from math_operations import add
# Now we can use the function directly without the module name
result = add(20, 7)
print(f"Result: {result}")
إعطاء اسم مستعار للوحدة باستخدام as
:
هذا مفيد جدًا مع الوحدات ذات الأسماء الطويلة.
# Import the module with a shorter alias 'mo'
import math_operations as mo
result = mo.add(100, 50)
print(f"Result: {result}")
2. ما هي الحزمة (Package)؟
عندما يصبح مشروعك كبيرًا جدًا ويحتوي على عشرات الوحدات، فإن وضعها كلها في مجلد واحد يصبح فوضويًا. الحزمة هي طريقة لتنظيم الوحدات المترابطة معًا داخل مجلد.
ببساطة، الحزمة هي أي مجلد يحتوي على ملف خاص باسم __init__.py
.
وجود هذا الملف (حتى لو كان فارغًا) يخبر بايثون بأن هذا المجلد ليس مجرد مجلد عادي، بل هو حزمة يمكن استيراد الوحدات منها.
هيكل مشروع يستخدم الحزم
لنتخيل أننا نوسع مشروع الآلة الحاسبة ليشمل عمليات حسابية بسيطة وأخرى معقدة. يمكننا تنظيم المشروع على النحو التالي:
calculator_project/
│
├── main.py
│
└── operations/
├── __init__.py
├── simple.py # (contains add, subtract)
└── complex.py # (contains power, sqrt)
ملف operations/simple.py
:
def add(x, y):
return x + y
def subtract(x, y):
return x - y
ملف operations/complex.py
:
import math
def power(base, exp):
return base ** exp
def square_root(number):
return math.sqrt(number)
ملف main.py
الرئيسي:
الآن، من ملف main.py
، يمكننا استيراد الدوال التي نحتاجها من داخل الحزمة operations
.
# Import specific functions from modules inside the 'operations' package
from operations.simple import add
from operations.complex import square_root
# Use the imported functions
sum_result = add(15, 10)
sqrt_result = square_root(64)
print(f"The sum is: {sum_result}")
print(f"The square root of 64 is: {sqrt_result}")
شرح هذه الجزئية:
هيكل الاستيراد الآن يتبع مسار المجلدات. from operations.simple import add
تعني: “من الحزمة operations
، من الوحدة simple
، قم باستيراد الدالة add
”. هذا الأسلوب يجعل المشاريع الكبيرة منظمة للغاية وسهلة الفهم.
3. تمرين تطبيقي: تنظيم تطبيق لتحويل الوحدات
المطلوب:
لديك برنامج يقوم بتحويلات بين وحدات مختلفة (درجات حرارة ومسافات). حاليًا، كل الكود موجود في ملف واحد. مهمتك هي إعادة تنظيمه باستخدام حزمة ووحدات منفصلة.
إرشادات الحل:
- أنشئ هيكل المشروع: قم بإنشاء مجلد رئيسي للمشروع (مثلاً
converter_app
). بداخله، أنشئ ملفmain.py
ومجلدًا جديدًا (حزمة) باسمconverters
. - أنشئ ملف
__init__.py
: داخل المجلدconverters
، أنشئ ملفًا فارغًا باسم__init__.py
لتعريف المجلد كحزمة. - أنشئ الوحدات: داخل الحزمة
converters
، أنشئ وحدتين:temperature.py
: ضع فيه دالة لتحويل درجة الحرارة من مئوية إلى فهرنهايت (celsius_to_fahrenheit
). المعادلة هي:(C * 9/5) + 32
.distance.py
: ضع فيه دالة لتحويل المسافة من كيلومتر إلى ميل (km_to_miles
). المعادلة هي:KM * 0.621371
.
- اكتب الكود الرئيسي: في ملف
main.py
، قم باستيراد الدوال التي أنشأتها من وحداتها الخاصة داخل حزمةconverters
. - استدعِ الدوال: في
main.py
، استدعِ الدوال مع قيم تجريبية واطبع النتائج لتتأكد من أن كل شيء يعمل بشكل صحيح.
الحل المقترح للتمرين
الخطوة 1: إنشاء هيكل الملفات والمجلدات بعد تنفيذ هذه الخطوة، يجب أن يبدو هيكل مشروعك هكذا:
converter_app/
│
├── main.py
│
└── converters/
├── __init__.py
└── distance.py
└── temperature.py
الخطوة 2: كتابة كود الوحدات
سنقوم الآن بملء الملفات داخل حزمة converters
.
ملف converters/temperature.py
:
def celsius_to_fahrenheit(celsius):
"""Converts Celsius to Fahrenheit."""
fahrenheit = (celsius * 9/5) + 32
return fahrenheit
شرح هذه الجزئية: هذه الوحدة الآن مسؤولة فقط عن التحويلات المتعلقة بدرجات الحرارة. أنشأنا دالة واحدة تؤدي هذه المهمة.
ملف converters/distance.py
:
def km_to_miles(kilometers):
"""Converts kilometers to miles."""
miles = kilometers * 0.621371
return miles
شرح هذه الجزئية: بالمثل، هذه الوحدة مسؤولة فقط عن التحويلات المتعلقة بالمسافات.
الخطوة 3: كتابة الكود الرئيسي
الآن، سنكتب الكود في ملف main.py
الذي سيقوم باستيراد واستخدام هذه الدوال.
# Import the specific functions we need from our package
from converters.temperature import celsius_to_fahrenheit
from converters.distance import km_to_miles
# --- Temperature Conversion ---
celsius_value = 25
fahrenheit_value = celsius_to_fahrenheit(celsius_value)
print(f"{celsius_value} degrees Celsius is equal to {fahrenheit_value:.2f} degrees Fahrenheit.")
# --- Distance Conversion ---
km_value = 100
miles_value = km_to_miles(km_value)
print(f"{km_value} kilometers is equal to {miles_value:.2f} miles.")
شرح هذه الجزئية:
from converters.temperature import ...
: نستورد الدالة التي نحتاجها من مسارها الصحيح داخل الحزمة.:.2f
: هذه صيغة متقدمة داخل f-string لتقريب الرقم العشري إلى منزلتين فقط، مما يجعل المخرجات أكثر أناقة.- الآن أصبح ملفنا الرئيسي نظيفًا جدًا وسهل القراءة. كل ما يفعله هو استدعاء الأدوات التي يحتاجها من الوحدات المتخصصة. إذا أردنا تعديل معادلة تحويل الحرارة، سنذهب مباشرة إلى ملف
temperature.py
دون لمس أي جزء آخر من البرنامج.
4. خلاصة الفصل
- الوحدات (Modules) هي ملفات بايثون تسمح لك بتقسيم الكود.
- الحزم (Packages) هي مجلدات تحتوي على وحدات مترابطة، ويجب أن تحتوي على ملف
__init__.py
. - استخدام الوحدات والحزم هو الممارسة الاحترافية لتنظيم المشاريع الكبيرة، مما يجعلها أسهل في الصيانة، الاختبار، والتطوير.
- نستخدم
import
وfrom
لجلب الكود من الوحدات والحزم إلى برامجنا.
ماذا بعد؟
في الفصل الرابع عشر، سنتعمق أكثر في بعض تقنيات بايثون المتقدمة التي تجعل كودك ليس فقط منظمًا، بل أيضًا أكثر أناقة وكفاءة، مثل تعبيرات القوائم والدوال المجهولة.