importهای مطلق و نسبی در پایتون

امیرحسین بیگدلو 4 ماه قبل

اگر روی یک پروژه پایتون کار کرده اید که بیش از یک فایل دارد، احتمالاً مجبور بوده اید از دستور import استفاده کنید.

 

حتی برای حرفه‌ای‌های پایتون که چند پروژه تحت پوشش خود دارد، import می تواند گیج کننده باشد! شما احتمالاً این مطلب را می خوانید زیرا می خواهید درک عمیق تری از import در پایتون، به ویژه نوع absolute و relative کسب کنید.

 

ویدیو پیشنهادی: کتابخانه استاندارد پایتون

 

# خلاصه ای سریع از import پایتون

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

 

چه اتفاقی می افتد وقتی در یک ماژول کدی دارید که نیاز به دسترسی به کد در یک ماژول یا پکیج دیگر دارد؟ شما آن را import می کنید!

 

 

+ import چطور کار میکند؟

اما import دقیقاً چگونه کار می کند؟ فرض کنید ماژول abc را به این شکل وارد می کنید:

import abc

 

اولین کاری که پایتون انجام می دهد این است که نام abc را در sys.modules جستجو کند. این حافظه پنهان همه ماژول هایی است که قبلاً وارد شده است.

 

اگر نام در حافظه پنهان ماژول یافت نشد، پایتون به جستجوی لیستی از ماژول های داخلی می پردازد. اینها ماژول هایی هستند که از قبل با پایتون نصب شده اند و در کتابخانه استاندارد پایتون یافت می شوند. اگر نام هنوز در ماژول های داخلی یافت نشد، پایتون آن را در لیستی از دایرکتوری های تعریف شده توسط sys.path جستجو می کند. این لیست معمولاً شامل دایرکتوری فعلی است که ابتدا جستجو می شود.

 

هنگامی که پایتون ماژول را پیدا می کند، آن را به نامی در محدوده محلی متصل می کند. این بدان معنی است که abc در حال حاضر تعریف شده است و می تواند در فایل فعلی بدون ایجاد NameError استفاده شود.

 

 

+ سینتکس import در پایتون

اکنون که می دانید دستور import چگونه کار می کند، بیایید سینتکس آن را بررسی کنیم. می توانید پکیج‌ها و ماژول ها را وارد کنید. همچنین می توانید آبجکت‌های خاصی را از یک پکیج یا ماژول وارد کنید.

 

به طور کلی دو نوع نحو import وجود دارد. وقتی از اولین مورد استفاده می کنید، منبع را مستقیماً وارد می کنید، مانند این:

import abc

abc می تواند یک پکیج یا یک ماژول باشد.

 

هنگامی که از شکل دوم استفاده می کنید، منبع را از پکیج یا ماژول دیگری وارد می کنید. در اینجا یک مثال است:

from abc import xyz

xyz می تواند ماژول، زیرپکیج یا شیء باشد، مانند کلاس یا تابع.

 

همچنین می توانید نام منبع وارد شده را تغییر دهید، مانند موارد زیر:

import abc as other_name

این کد نام منبع وارد شده abc را به other_name در اسکریپت تغییر می دهد. اکنون باید به عنوان other_name ارجاع داده شود، در غیر این صورت شناخته نمی شود.

 

مقاله پیشنهادی: برنامه نویسی شی گرا چیست؟

 

+ استایل دهی import در پایتون

PEP 8، راهنمای سبک رسمی پایتون، هنگام نوشتن دستور import چند نکته دارد. در اینجا خلاصه ای آمده است:

 

1. import باید همیشه در بالای فایل، پس از هرگونه کامنت ماژول و docstring، نوشته شود.

2. import باید بر اساس آنچه وارد می شود تقسیم شود. به طور کلی سه گروه وجود دارد:

  • import کتابخانه استاندارد (ماژول های داخلی پایتون)
  • import پکیج‌های شخص ثالث (ماژول هایی که نصب شده اند و به برنامه فعلی تعلق ندارند)
  • import برنامه محلی (ماژول هایی که متعلق به برنامه فعلی است)

3. هر گروه از import باید با یک فضای خالی از هم جدا شوند.

 

همچنین ایده خوبی است که import خود را بر اساس حروف الفبا در هر گروه import مرتب کنید. این امر پیدا کردن import خاص را بسیار ساده تر می کند، به ویژه هنگامی که import زیادی در یک فایل وجود داشته باشد.

 

در اینجا نمونه ای از نحوه ایجاد دستورات import آورده شده است:

"""Illustration of good import statement styling.

Note that the imports come after the docstring.

"""

# Standard library imports
import datetime
import os

# Third party imports
from flask import Flask
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy

# Local application imports
from local_module import local_class
from local_package import local_function

 

دستورات import بالا به سه گروه مجزا تقسیم می شوند که با یک فاصله خالی از هم جدا می شوند. آنها همچنین به ترتیب حروف الفبا در هر گروه مرتب شده اند.

 

مقاله پیشنهادی: چطور اسکریپت های پایتون را اجرا کنیم؟

 

# Absolute imports

شما در مورد نحوه نوشتن دستورات import و نحوه ایجاد آنها مانند یک حرفه ای بسیار سریع عمل کرده اید. اکنون وقت آن است که کمی بیشتر در مورد import مطلق بیاموزیم.

 

import مطلق، منبعی را که باید با استفاده از مسیر کامل آن از پوشه اصلی پروژه وارد شود، مشخص می کند.

 

+ سینتکس و مثالهای عملی

فرض کنید ساختار دایرکتوری زیر را دارید:

└── project
    ├── package1
    │   ├── module1.py
    │   └── module2.py
    └── package2
        ├── __init__.py
        ├── module3.py
        ├── module4.py
        └── subpackage1
            └── module5.py

 

یک دایرکتوری project وجود دارد که شامل دو زیردایرکتوری، package1 و package2 است. دایرکتوری package1 دارای دو فایل module1.py و module2.py است.

 

دایرکتوری package2 دارای سه فایل است: دو ماژول، module3.py و module4.py، و یک فایل مقداردهی اولیه، __init__.py. همچنین شامل یک دایرکتوری، subpackage1 است که به نوبه خود حاوی یک فایل module5.py است.

 

بیایید موارد زیر را فرض کنیم:

1. package1/module2.py شامل یک تابع ، function1 است.

2. package2/__ init__.py شامل یک کلاس، class1 است.

3. package2/subpackage1/module5.py شامل یک تابع، function2 است.

 

موارد زیر نمونه های عملی import مطلق است:

from package1 import module1
from package1.module2 import function1
from package2 import class1
from package2.subpackage1.module5 import function2

 

توجه داشته باشید که باید یک مسیر دقیق برای هر بسته یا فایل، از پوشه پکیج سطح بالا ارائه دهید. این تا حدودی شبیه به مسیر فایل آن است، اما ما به جای یک علامت (/) از نقطه (.) استفاده می کنیم.

 

مقاله پیشنهادی: 11 کتابخانه پایتونی که هر برنامه نویسی باید بداند

 

+ مزایا و معایب import مطلق

import مطلق به import نسبی ترجیح داده می شود زیرا کاملاً واضح و سرراست است. به آسانی می توان فقط با مشاهده دستور گفت که منبع وارد شده کجاست. علاوه بر این، import مطلق معتبر می ماند حتی اگر مکان فعلی دستور import تغییر کند. در واقع، PEP 8 به صراحت import مطلق را توصیه می کند.

 

با این حال، گاهی اوقات، بسته به پیچیدگی ساختار دایرکتوری، import مطلق می تواند طولانی باشد. تصور کنید چنین گزاره ای داشته باشید:

from package1.subpackage2.subpackage3.subpackage4.module5 import function6

این مسخره است، درست است؟ خوشبختانه import نسبی در چنین مواردی جایگزین مناسبی است!

 

 

# Relative imports

import نسبی منبعی را که باید نسبت به مکان فعلی وارد شود، یعنی مکانی که دستور import در آن قرار دارد، مشخص می کند. دو نوع import نسبی وجود دارد: ضمنی و صریح. import نسبی ضمنی در پایتون 3 منسوخ شده است، بنابراین من آنها را در اینجا پوشش نمی دهم.

 

+ نحو و مثالهای عملی

نحو یک import نسبی بستگی به مکان فعلی و همچنین محل ماژول، پکیج یا شیئی که باید وارد شود، دارد. در اینجا چند نمونه از import نسبی آورده شده است:

from .some_module import some_class
from ..some_package import some_function
from . import some_class

 

می بینید که حداقل یک نقطه در هر دستور import در بالا وجود دارد. در import نسبی از نماد نقطه برای تعیین مکان استفاده می شود.

 

یک نقطه به این معنی است که ماژول یا پکیج مورد اشاره در همان دایرکتوری مکان فعلی قرار دارد. دو نقطه به این معنی است که در دایرکتوری والد محل فعلی قرار دارد - یعنی فهرست بالا. سه نقطه به این معنی است که در دایرکتوری پدربزرگ است و غیره. اگر از سیستم عامل مشابه یونیکس استفاده می کنید، احتمالاً برای شما آشنا خواهد بود!

 

فرض کنید شما همان ساختار دایرکتوری قبلی را دارید:

└── project
    ├── package1
    │   ├── module1.py
    │   └── module2.py
    └── package2
        ├── __init__.py
        ├── module3.py
        ├── module4.py
        └── subpackage1
            └── module5.py

 

محتویات فایل را به یاد بیاورید:

1. package1/module2.py شامل یک تابع ، function1 است.

2. package2/__ init__.py شامل یک کلاس، class1 است.

3. package2/subpackage1/module5.py شامل یک تابع، function2 است.

 

شما می توانید function1 را در فایل package1/module1.py از این طریق وارد کنید:

# package1/module1.py

from .module2 import function1

 

در اینجا فقط از یک نقطه استفاده می کنید زیرا module2.py در همان دایرکتوری ماژول فعلی قرار دارد که module1.py است.

 

شما می توانید class1 و function2 را به این روش در فایل package2/module3.py وارد کنید:

# package2/module3.py

from . import class1
from .subpackage1.module5 import function2

 

در اولین دستور import، یک نقطه به این معنی است که شما کلاس 1 را از پکیج فعلی وارد می کنید. به یاد داشته باشید که وارد کردن یک پکیج در اصل فایل __init__.py بسته را به عنوان یک ماژول وارد می کند.

 

در دومین دستور import، مجدداً از یک نقطه استفاده می کنید زیرا subpackage1 در همان دایرکتوری ماژول فعلی، که module3.py است، قرار دارد.

 

مقاله پیشنهادی: آموزش کار با api در پایتون

 

+ مزایا و معایب import نسبی

یک مزیت آشکار import نسبی این است که آنها کاملاً مختصر هستند. بسته به مکان فعلی، آنها می توانند دستور import مسخره طولانی را که قبلاً مشاهده کرده اید به چیزی ساده تبدیل کنند:

from ..subpackage4.module5 import function6

 

متأسفانه، import نسبی می تواند نامرتب باشد، به ویژه برای پروژه های مشترک که ساختار دایرکتوری به احتمال زیاد تغییر می کند. import نسبی نیز به اندازه مطلق قابل خواندن نیست و تشخیص محل منابع وارداتی نیز کار آسانی نیست.

 

 

# نتیجه گیری

اکنون نحوه عملکرد import را می دانید. شما بهترین شیوه ها را برای نوشتن دستورات import آموخته اید و تفاوت بین import مطلق و نسبی را می دانید.

 

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

 

مطالب مشابه



مونگارد