خانه / آموزش‌ها / ساختار و پکیج‌بندی پروژه در پایتون

ساختار و پکیج‌بندی پروژه در پایتون

🐍 HomeOfPython
|
📅 1404/10/17

سطح مقدماتی (Beginner Level)

در شروع یادگیری پایتون، معمولاً تمام کدها در یک فایل تکی (مثلاً main.py) نوشته می‌شوند. اما با بزرگ‌تر شدن پروژه، نگهداری هزاران خط کد در یک فایل غیرممکن می‌شود. در این سطح، یاد می‌گیریم چگونه کدها را به ماژول‌ها و پکیج‌ها تقسیم کنیم.

۱. مفهوم ماژول و پکیج (Modules & Packages)

ساده‌ترین روش سازماندهی، تبدیل کد به ماژول (یک فایل .py) و پکیج (پوشه‌ای حاوی فایل __init__.py) است.

  • ماژول: هر فایل پایتون یک ماژول است.
  • پکیج: پوشه‌ای که شامل ماژول‌ها و یک فایل مخصوص به نام __init__.py باشد.

مثال اول: ساختار مسطح (Flat Structure)

این ساختار برای اسکریپت‌های کوچک و پروژه‌های ساده مناسب است.

text
my_project/
│
├── main.py            # نقطه ورود برنامه
├── utils.py           # توابع کمکی (ماژول)
└── requirements.txt   # وابستگی‌ها

مثال دوم: کد ماژولار (Static)

در این حالت فایل utils.py توابعی دارد که در main.py استفاده می‌شوند. چون این کدها به فایل‌های جداگانه نیاز دارند، به صورت استاتیک نمایش داده می‌شوند.

python
# utils.py
def calculate_vat(price):
    return price * 0.09
python
# main.py
from utils import calculate_vat

price = 100000
print(f"Final Price: {price + calculate_vat(price)}")

مثال سوم: بررسی مسیرهای ایمپورت (Interactive)

در پایتون، پکیج‌ها بر اساس sys.path پیدا می‌شوند. کد زیر نشان می‌دهد پایتون کجا دنبال فایل‌ها می‌گردد:

Python

۲. فایل‌های ضروری پروژه (Essential Files)

هر پروژه استاندارد پایتون نیاز به فایل‌های جانبی دارد تا دیگران بتوانند از آن استفاده کنند.

  • requirements.txt: لیست کتابخانه‌های مورد نیاز.
  • README.md: توضیحات پروژه.
  • .gitignore: فایل‌هایی که نباید در گیت ذخیره شوند.

مثال اول: محتوای requirements.txt (Static)

text
requests==2.31.0
numpy>=1.24.0
pandas

مثال دوم: فایل gitignore. (Static)

جلوگیری از آپلود فایل‌های موقت و محیط مجازی.

text
__pycache__/
venv/
.env
*.pyc

مثال سوم: شبیه‌سازی خواندن فایل کانفیگ (Interactive)

فرض کنید یک فایل تنظیمات ساده داریم. کد زیر نحوه مدیریت مسیر فایل‌ها نسبت به محل اجرای اسکریپت را نشان می‌دهد:

Python

سطح پیشرفته (Professional Level)

در پروژه‌های حرفه‌ای، کتابخانه‌های متن‌باز (Open Source) و اپلیکیشن‌های سازمانی، ساختار ساده (Flat) باعث مشکلاتی مثل "Import Side Effects" و تداخل نام‌ها می‌شود. در اینجا با ساختارهای مدرن و استاندارد بسته‌بندی (Packaging) آشنا می‌شویم.

۱. ساختار SRC Layout

استاندارد واقعی (De Facto) در پروژه‌های مدرن پایتون، استفاده از پوشه src است. این ساختار شما را مجبور می‌کند که پکیج خود را نصب کنید تا قابل استفاده باشد (حتی در حالت توسعه)، که این کار تست‌ها را واقعی‌تر می‌کند.

ساختار دایرکتوری (Structure Definition)

text
my_project/
│
├── src/
│   └── mypackage/
│       ├── __init__.py
│       ├── core.py
│       └── api.py
│
├── tests/
│   ├── __init__.py
│   └── test_core.py
│
├── pyproject.toml    # تنظیمات مدرن بیلد
├── setup.py          # (قدیمی‌تر) تنظیمات بیلد
└── README.md

مثال اول: فایل __init__.py حرفه‌ای (Static)

در سطح پیشرفته، از __init__.py برای کنترل فضای نام (Namespace) و اکسپورت کردن کلاس‌های اصلی استفاده می‌شود تا کاربر نیاز نباشد مسیرهای طولانی را ایمپورت کند.

python
# src/mypackage/__init__.py

from .core import MainClass
from .api import public_function

# محدود کردن آنچه با import * در دسترس است
__all__ = ["MainClass", "public_function"]

__version__ = "1.0.0"

مثال دوم: شبیه‌سازی ساختار پکیج (Interactive)

این اسکریپت مفهوم __package__ و ایمپورت‌های نسبی را نشان می‌دهد (شبیه‌سازی منطق داخلی پکیج):

Python

۲. پیکربندی مدرن با pyproject.toml

در گذشته از setup.py استفاده می‌شد، اما استاندارد جدید (PEP 517/518) استفاده از pyproject.toml است. این فایل تمام تنظیمات پروژه، وابستگی‌های بیلد و تنظیمات ابزارها (مثل Black, Ruff, Pytest) را یکجا نگه می‌دارد.

مثال اول: پیکربندی با Setuptools (Static)

تنظیمات استاندارد برای یک پروژه مبتنی بر src.

toml
# pyproject.toml
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "awesome_package"
version = "0.0.1"
authors = [
  { name="HomeOfPython", email="info@homeofpython.com" },
]
description = "A comprehensive guide example"
requires-python = ">=3.8"
classifiers = [
    "Programming Language :: Python :: 3",
    "License :: OSI Approved :: MIT License",
]
dependencies = [
    "requests",
]

[project.urls]
"Homepage" = "https://github.com/homeofpython/example"

مثال دوم: پیکربندی با Poetry (Static)

ابزار Poetry مدیریت وابستگی‌ها را بسیار ساده می‌کند.

toml
# pyproject.toml (Poetry Style)
[tool.poetry]
name = "awesome_package"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]

[tool.poetry.dependencies]
python = "^3.9"
fastapi = "^0.100.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

۳. فایل‌های غیر کدی (Data Files & Manifest)

گاهی نیاز دارید فایل‌هایی مثل json, csv یا تصاویر را همراه پکیج خود منتشر کنید. پایتون به صورت پیش‌فرض فقط فایل‌های .py را در بیلد نهایی قرار می‌دهد. برای حل این مشکل از MANIFEST.in یا تنظیمات package_data استفاده می‌شود.

مثال اول: فایل MANIFEST.in (Static)

دستورالعمل‌هایی برای گنجاندن فایل‌های استاتیک.

text
include README.md
include LICENSE
recursive-include src/mypackage/templates *.html
recursive-include src/mypackage/data *.json
global-exclude *.pyc

مثال دوم: دسترسی به منابع در کد (Interactive)

روش حرفه‌ای برای خواندن فایل‌های دیتا داخل پکیج، استفاده از importlib.resources است (جایگزین روش قدیمی __file__).

Python

۴. تست و خودکارسازی (Testing & Automation)

ساختار حرفه‌ای شامل پوشه tests خارج از سورس کد است. همچنین ابزارهایی مثل Tox یا Nox برای تست در محیط‌های مختلف استفاده می‌شوند.

ساختار تست

مثال اول: ساختار فایل‌های تست (Static)

تست‌ها باید ساختار پکیج اصلی را آینه‌وار تکرار کنند.

text
tests/
├── __init__.py
├── conftest.py          # تنظیمات و فیکسچرهای Pytest
├── unit/                # تست‌های واحد
│   ├── test_core.py
│   └── test_api.py
└── integration/         # تست‌های یکپارچگی
    └── test_database.py

مثال دوم: اجرای یک تست واحد ساده (Interactive)

کد زیر نشان می‌دهد چطور می‌توان یک کلاس تست ساده (شبیه به unittest) نوشت و اجرا کرد.

Python