آموزش پایتون, پایتون سطح متوسط

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

ماژول‌ها و پکیج‌ها در پایتون؛ آموزش 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 calculatorcalculator.add(2, 3)مشخص است تابع متعلق به کدام ماژول است.
from calculator import addadd(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، پایتون معمولاً در این مسیرها به‌دنبال ماژول می‌گردد:

  1. پوشه فایل در حال اجرا
  2. مسیرهای ثبت‌شده در متغیر محیطی PYTHONPATH
  3. پوشه‌های کتابخانه استاندارد
  4. پوشه نصب پکیج‌های خارجی مانند 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]))

با این ساختار، فایل اصلی فقط نحوه استفاده از قابلیت‌ها را نشان می‌دهد و جزئیات هر عملیات در ماژول مربوط به خود قرار دارد.

تمرین‌های درس

  1. ماژولی با نام text_tools.py بسازید که توابع شمارش کلمات، تبدیل متن به حروف بزرگ و حذف فاصله‌های ابتدا و انتهای متن را داشته باشد.
  2. ماژولی با نام validators.py بسازید که اعتبار طول رمز عبور و مثبت‌بودن یک عدد را بررسی کند.
  3. پکیجی با نام geometry بسازید و محاسبه مساحت دایره، مستطیل و مثلث را در ماژول‌های جداگانه قرار دهید.
  4. برای یکی از ماژول‌ها بخش if __name__ == "__main__": اضافه کنید و چند آزمایش ساده بنویسید.
  5. عمداً نام یک فایل را random.py بگذارید، رفتار import را بررسی کنید و سپس نام فایل را اصلاح کنید.

اشتباهات رایج

  • قرار دادن کد اجرایی زیاد در سطح اصلی ماژول، به‌طوری‌که هنگام import ناخواسته اجرا شود.
  • استفاده گسترده از from module import *.
  • انتخاب نام‌هایی که با کتابخانه استاندارد تداخل دارند.
  • ساخت ماژول‌هایی بسیار بزرگ با چند مسئولیت نامرتبط.
  • ایجاد importهای حلقوی میان فایل‌ها.
  • اجرای فایل‌های داخلی پکیج به شکلی که مسیر import را خراب کند.

جمع‌بندی

در این درس یاد گرفتیم که هر فایل .py می‌تواند یک ماژول باشد و یک پکیج چند ماژول مرتبط را در یک پوشه سازمان‌دهی می‌کند. روش‌های import، from ... import و as را بررسی کردیم، با کاربرد __name__ و __init__.py آشنا شدیم و یک ماشین‌حساب ماژولار ساختیم.

تقسیم برنامه به ماژول‌های کوچک و هدفمند، یکی از مهم‌ترین گام‌ها برای حرکت از اسکریپت‌های ساده به پروژه‌های واقعی پایتون است. در درس بعدی، با نصب کتابخانه‌ها توسط pip و ساخت محیط مجازی با venv آشنا می‌شویم تا وابستگی‌های هر پروژه را مستقل مدیریت کنیم.

ادامه مسیر یادگیری پایتون

برای یادگیری منظم، آموزش‌های مرتبط زیر را به‌ترتیب دنبال کنید:

📌 همچنین بخوانید: بازار کار پایتون در ایران، دستورهای break، continue و pass در پایتون و ساخت ربات تلگرام با پایتون

می‌خواهی پیشرفتت ذخیره شود؟با ورود یا ثبت‌نام رایگان، درس‌های تمام‌شده را علامت بزن و درصد پیشرفتت را در حساب کاربری ببین.ورود / ثبت‌نام برای ذخیره پیشرفت
درس بعدی · دوره پایتون متوسط (14 از 18)نصب کتابخانه با pip و ساخت محیط مجازی venv در پایتون ←
آموزش‌های تازه، کد آماده و رفع خطاهر هفته در کانال Dev Source؛ رایگان.
🧭 مسیر یادگیری پایتون از صفر
ماژول 8: ماژول‌ها و کتابخانه‌ها — درس 35 از 44

برای ذخیره پیشرفت در همه دستگاه‌ها و دریافت گواهی پایان مسیر، رایگان ثبت‌نام کن یا وارد شو.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *