ماژولها و پکیجها در پایتون؛ آموزش import و ساخت Package

🗓 آخرین بهروزرسانی:
ماژولها و پکیجها به شما کمک میکنند کدهای پایتون را به فایلها و بخشهای کوچکتر تقسیم کنید، دوباره از آنها استفاده کنید و پروژههای بزرگتر را منظم نگه دارید. هر فایل پایتون میتواند یک ماژول باشد و چند ماژول مرتبط نیز میتوانند در قالب یک پکیج کنار هم قرار بگیرند.
این مطلب، درس سیزدهم از دوره رایگان پایتون سطح متوسط است. در درس قبلی کار با فایلهای JSON را یاد گرفتیم. اکنون میخواهیم ساختار برنامه را حرفهایتر کنیم تا همه کدها در یک فایل طولانی قرار نگیرند.
ماژول در پایتون چیست؟
ماژول یا Module معمولاً یک فایل با پسوند .py است که میتواند شامل متغیرها، توابع، کلاسها و کدهای اجرایی باشد. هدف اصلی ماژول این است که یک بخش مشخص از برنامه را جدا و قابل استفاده مجدد کند.
برای نمونه، بهجای قرار دادن تمام توابع ریاضی، اعتبارسنجی ورودی، مدیریت فایل و منوی برنامه در یک فایل، میتوانیم هر بخش را در یک ماژول جداگانه قرار دهیم:
project/
├── main.py
├── calculator.py
├── validators.py
└── file_manager.pyدر این ساختار، فایل calculator.py مسئول محاسبات، فایل validators.py مسئول بررسی ورودیها و فایل file_manager.py مسئول کار با فایلها است. فایل main.py نیز این بخشها را به هم متصل میکند.
چرا باید از ماژولها استفاده کنیم؟
- خوانایی بهتر: هر فایل یک مسئولیت مشخص دارد و پیدا کردن کدها آسانتر میشود.
- استفاده مجدد: یک تابع را میتوان در چند برنامه یا چند بخش پروژه استفاده کرد.
- رفع خطای سادهتر: خطاها در بخشهای کوچکتر سریعتر پیدا میشوند.
- همکاری تیمی: افراد مختلف میتوانند روی ماژولهای جداگانه کار کنند.
- توسعهپذیری: افزودن قابلیت جدید بدون شلوغکردن فایل اصلی امکانپذیر میشود.
- آزمایشپذیری: توابع و کلاسهای هر ماژول را میتوان مستقل آزمایش کرد.
ساخت اولین ماژول پایتون
در یک پوشه، دو فایل با نامهای calculator.py و main.py بسازید.
محتوای فایل calculator.py:
def add(a, b):
return a + b
def subtract(a, b):
return a - b
pi = 3.14159این فایل شامل دو تابع و یک متغیر است. اکنون در فایل main.py ماژول را وارد میکنیم:
import calculator
result = calculator.add(10, 5)
print(result)
print(calculator.pi)خروجی:
15
3.14159پس از import calculator برای دسترسی به اعضای ماژول، نام ماژول و سپس نقطه را مینویسیم؛ مانند calculator.add.
واردکردن بخش مشخصی از ماژول با from
اگر فقط به یک یا چند عضو مشخص نیاز داریم، میتوانیم از دستور from ... import ... استفاده کنیم:
from calculator import add, subtract
print(add(8, 4))
print(subtract(8, 4))در این حالت دیگر لازم نیست قبل از نام تابع، calculator. نوشته شود.
تفاوت import و from import
| روش | نمونه استفاده | مزیت |
|---|---|---|
import calculator | calculator.add(2, 3) | مشخص است تابع متعلق به کدام ماژول است. |
from calculator import add | add(2, 3) | کد کوتاهتر میشود. |
در پروژههای بزرگ، روش اول اغلب خواناتر است؛ زیرا منبع تابع یا متغیر را بهوضوح نشان میدهد.
استفاده از نام مستعار با as
گاهی نام یک ماژول طولانی است یا ممکن است با نام دیگری در برنامه تداخل داشته باشد. در این شرایط از as استفاده میکنیم:
import calculator as calc
print(calc.add(20, 7))برای عضو واردشده نیز میتوان نام مستعار تعیین کرد:
from calculator import subtract as minus
print(minus(15, 6))کتابخانههای مشهور نیز نامهای مستعار رایجی دارند؛ برای مثال در بسیاری از پروژهها numpy با نام np و pandas با نام pd وارد میشوند.
چرا import * توصیه نمیشود؟
دستور زیر تمام نامهای عمومی یک ماژول را وارد میکند:
from calculator import *این روش معمولاً توصیه نمیشود؛ زیرا:
- مشخص نیست هر نام از کدام ماژول آمده است.
- ممکن است نامها یکدیگر را بازنویسی کنند.
- خواندن و نگهداری کد دشوارتر میشود.
- ابزارهای تحلیل کد نمیتوانند وابستگیها را بهخوبی تشخیص دهند.
بهتر است خود ماژول یا اعضای موردنیاز را بهصورت صریح وارد کنید.
ماژولهای داخلی پایتون
پایتون همراه با مجموعه بزرگی از ماژولهای آماده عرضه میشود که به آن کتابخانه استاندارد پایتون میگویند. برای استفاده از این ماژولها معمولاً نیازی به نصب جداگانه ندارید.
ماژول math
import math
print(math.sqrt(81))
print(math.ceil(4.2))
print(math.floor(4.8))
print(math.pi)ماژول random
import random
number = random.randint(1, 10)
item = random.choice(["Python", "Django", "FastAPI"])
print(number)
print(item)ماژول pathlib
from pathlib import Path
file_path = Path("data") / "users.json"
print(file_path)
print(file_path.suffix)ماژول pathlib برای ساخت و مدیریت مسیر فایلها بهشکل خوانا و مستقل از سیستمعامل مفید است.
مشاهده اعضای یک ماژول با dir
تابع داخلی dir() فهرستی از نامهای تعریفشده در یک ماژول یا شیء را نمایش میدهد:
import math
print(dir(math))برای مشاهده راهنمای یک تابع یا ماژول نیز میتوان از help() استفاده کرد:
help(math.sqrt)این ابزارها برای یادگیری و بررسی سریع امکانات ماژولها مناسباند، هرچند مستندات رسمی هر کتابخانه معمولاً اطلاعات کاملتری ارائه میدهد.
متغیر __name__ در پایتون
پایتون برای هر ماژول یک متغیر ویژه با نام __name__ تعیین میکند. اگر فایل مستقیماً اجرا شود، مقدار این متغیر برابر "__main__" است. اگر همان فایل در فایل دیگری import شود، مقدار آن نام ماژول خواهد بود.
فایل calculator.py را بهصورت زیر تغییر دهید:
def add(a, b):
return a + b
def subtract(a, b):
return a - b
if __name__ == "__main__":
print("Testing calculator module")
print(add(2, 3))اگر calculator.py را مستقیم اجرا کنید، کد بخش شرط اجرا میشود. اما اگر آن را در main.py وارد کنید، فقط توابع تعریف میشوند و پیام آزمایشی نمایش داده نمیشود.
این الگو برای جداسازی کد قابل استفاده مجدد از کد اجرایی یا آزمایشی بسیار مهم است.
پکیج در پایتون چیست؟
پکیج یا Package پوشهای است که چند ماژول مرتبط را در یک ساختار منظم نگه میدارد. برای نمونه، یک پکیج فروشگاه میتواند ماژولهای محصولات، سفارشها و پرداخت را شامل شود:
shop/
├── __init__.py
├── products.py
├── orders.py
└── payments.py
main.pyدر نسخههای جدید پایتون، بعضی پوشهها بدون فایل __init__.py نیز میتوانند بهعنوان namespace package شناسایی شوند؛ اما برای پکیجهای معمولی و آموزشی، وجود این فایل ساختار را روشنتر و سازگاری را بیشتر میکند.
ساخت یک پکیج ساده
پوشهای با نام shop بسازید و داخل آن فایلهای زیر را قرار دهید.
فایل shop/products.py:
def calculate_discount(price, percent):
discount = price * percent / 100
return price - discountفایل shop/orders.py:
def create_order(customer, product):
return {
"customer": customer,
"product": product,
"status": "new"
}فایل shop/__init__.py میتواند در ابتدا خالی باشد:
# shop packageاکنون در فایل main.py از ماژولهای داخل پکیج استفاده کنید:
from shop.products import calculate_discount
from shop.orders import create_order
final_price = calculate_discount(500000, 20)
order = create_order("مهران", "دوره پایتون")
print(final_price)
print(order)واردکردن اعضا از طریق __init__.py
میتوانیم اعضای پرکاربرد پکیج را در فایل __init__.py در دسترس قرار دهیم.
محتوای shop/__init__.py:
from .products import calculate_discount
from .orders import create_orderسپس در فایل اصلی واردکردن کوتاهتر میشود:
from shop import calculate_discount, create_order
print(calculate_discount(800000, 10))
print(create_order("Sara", "Keyboard"))نقطه قبل از نام ماژول در .products و .orders به پایتون میگوید که این ماژولها در همین پکیج قرار دارند.
واردکردن مطلق و نسبی
در یک پکیج، دو روش اصلی برای import وجود دارد:
واردکردن مطلق
from shop.products import calculate_discountمسیر از نام اصلی پکیج شروع میشود. این روش معمولاً واضحتر است.
واردکردن نسبی
from .products import calculate_discountنقطه به پوشه فعلی اشاره میکند. دو نقطه .. به پکیج والد اشاره دارد. واردکردن نسبی بیشتر داخل فایلهای خود پکیج استفاده میشود.
پایتون ماژولها را کجا جستوجو میکند؟
هنگام import، پایتون معمولاً در این مسیرها بهدنبال ماژول میگردد:
- پوشه فایل در حال اجرا
- مسیرهای ثبتشده در متغیر محیطی
PYTHONPATH - پوشههای کتابخانه استاندارد
- پوشه نصب پکیجهای خارجی مانند
site-packages
میتوانید مسیرهای جستوجو را مشاهده کنید:
import sys
for path in sys.path:
print(path)در پروژههای عادی بهتر است بهجای تغییر دستی sys.path، ساختار پوشهها و روش اجرای پروژه را اصلاح کنید.
خطای ModuleNotFoundError
اگر پایتون ماژول موردنظر را پیدا نکند، خطایی شبیه زیر نمایش داده میشود:
ModuleNotFoundError: No module named 'calculator'دلایل رایج این خطا عبارتاند از:
- نام فایل یا پکیج اشتباه نوشته شده است.
- فایل در پوشهای قرار دارد که در مسیر جستوجوی پایتون نیست.
- برنامه از پوشه نامناسب اجرا شده است.
- کتابخانه خارجی در محیط فعال نصب نشده است.
- نام فایل شما با یک ماژول استاندارد یا کتابخانه نصبشده تداخل دارد.
برای مثال، فایل خود را random.py یا json.py نامگذاری نکنید؛ زیرا ممکن است هنگام import random یا import json فایل شما بهجای ماژول استاندارد بارگذاری شود.
تفاوت ماژول، پکیج و کتابخانه
| مفهوم | تعریف ساده | نمونه |
|---|---|---|
| ماژول | یک فایل پایتون شامل کد قابل استفاده مجدد | calculator.py |
| پکیج | پوشهای شامل چند ماژول مرتبط | shop/ |
| کتابخانه | مجموعهای از ماژولها و پکیجها برای حل یک حوزه مسئله | کتابخانه استاندارد پایتون یا Requests |
| فریمورک | ساختاری گسترده که جریان کلی برنامه را تعیین میکند | Django |
این اصطلاحها گاهی در گفتوگوی روزمره بهجای یکدیگر استفاده میشوند، اما تفاوت مفهومی آنها برای طراحی پروژه مهم است.
نکات نامگذاری ماژولها و پکیجها
- نامها را کوتاه، توصیفی و با حروف کوچک انتخاب کنید.
- برای جداکردن واژهها از زیرخط استفاده کنید؛ مانند
file_manager.py. - از فاصله، خط تیره و حروف فارسی در نام فایلهای کد استفاده نکنید.
- نام فایل را با ماژولهای استاندارد مانند
math.py،json.pyیاrandom.pyیکسان نگذارید. - هر ماژول را روی یک مسئولیت مشخص متمرکز کنید.
- از ایجاد وابستگی حلقوی میان ماژولها جلوگیری کنید.
وابستگی حلقوی چیست؟
وابستگی حلقوی زمانی رخ میدهد که ماژول اول، ماژول دوم را import کند و ماژول دوم نیز دوباره ماژول اول را import کند. این وضعیت ممکن است باعث خطای import یا دسترسینداشتن به اعضایی شود که هنوز تعریف نشدهاند.
راههای کاهش این مشکل:
- کد مشترک را به یک ماژول سوم منتقل کنید.
- مسئولیت ماژولها را دوباره طراحی کنید.
- در موارد خاص، import را داخل تابع انجام دهید؛ ولی این راهحل نباید جای طراحی صحیح را بگیرد.
- وابستگیها را یکطرفه و روشن نگه دارید.
پروژه عملی: ماشینحساب ماژولار
در این تمرین، یک ماشینحساب کوچک را به چند فایل تقسیم میکنیم.
ساختار پروژه:
modular_calculator/
├── main.py
└── operations/
├── __init__.py
├── basic.py
└── advanced.pyفایل operations/basic.py:
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
raise ValueError("تقسیم بر صفر مجاز نیست")
return a / bفایل operations/advanced.py:
def power(base, exponent):
return base ** exponent
def average(numbers):
if not numbers:
raise ValueError("لیست اعداد نباید خالی باشد")
return sum(numbers) / len(numbers)فایل operations/__init__.py:
from .basic import add, subtract, multiply, divide
from .advanced import power, averageفایل main.py:
from operations import add, subtract, multiply, divide
from operations import power, average
print(add(12, 8))
print(subtract(12, 8))
print(multiply(12, 8))
print(divide(12, 4))
print(power(2, 5))
print(average([10, 15, 20]))با این ساختار، فایل اصلی فقط نحوه استفاده از قابلیتها را نشان میدهد و جزئیات هر عملیات در ماژول مربوط به خود قرار دارد.
تمرینهای درس
- ماژولی با نام
text_tools.pyبسازید که توابع شمارش کلمات، تبدیل متن به حروف بزرگ و حذف فاصلههای ابتدا و انتهای متن را داشته باشد. - ماژولی با نام
validators.pyبسازید که اعتبار طول رمز عبور و مثبتبودن یک عدد را بررسی کند. - پکیجی با نام
geometryبسازید و محاسبه مساحت دایره، مستطیل و مثلث را در ماژولهای جداگانه قرار دهید. - برای یکی از ماژولها بخش
if __name__ == "__main__":اضافه کنید و چند آزمایش ساده بنویسید. - عمداً نام یک فایل را
random.pyبگذارید، رفتار import را بررسی کنید و سپس نام فایل را اصلاح کنید.
اشتباهات رایج
- قرار دادن کد اجرایی زیاد در سطح اصلی ماژول، بهطوریکه هنگام import ناخواسته اجرا شود.
- استفاده گسترده از
from module import *. - انتخاب نامهایی که با کتابخانه استاندارد تداخل دارند.
- ساخت ماژولهایی بسیار بزرگ با چند مسئولیت نامرتبط.
- ایجاد importهای حلقوی میان فایلها.
- اجرای فایلهای داخلی پکیج به شکلی که مسیر import را خراب کند.
جمعبندی
در این درس یاد گرفتیم که هر فایل .py میتواند یک ماژول باشد و یک پکیج چند ماژول مرتبط را در یک پوشه سازماندهی میکند. روشهای import، from ... import و as را بررسی کردیم، با کاربرد __name__ و __init__.py آشنا شدیم و یک ماشینحساب ماژولار ساختیم.
تقسیم برنامه به ماژولهای کوچک و هدفمند، یکی از مهمترین گامها برای حرکت از اسکریپتهای ساده به پروژههای واقعی پایتون است. در درس بعدی، با نصب کتابخانهها توسط pip و ساخت محیط مجازی با venv آشنا میشویم تا وابستگیهای هر پروژه را مستقل مدیریت کنیم.
ادامه مسیر یادگیری پایتون
برای یادگیری منظم، آموزشهای مرتبط زیر را بهترتیب دنبال کنید:
📌 همچنین بخوانید: بازار کار پایتون در ایران، دستورهای break، continue و pass در پایتون و ساخت ربات تلگرام با پایتون
برای ذخیره پیشرفت در همه دستگاهها و دریافت گواهی پایان مسیر، رایگان ثبتنام کن یا وارد شو.