شنبه ۲۹ دي ۱۴۰۳
Tut24 آموزش برنامه نویسی و مجله تخصصی فناوری ورود/عضویت

آموزش پایتون - ماژول‌ها

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

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

مثال

 در اینجا مثالی از یک ماژول ساده به نام support.py آورده شده است.

def print_func( par ):
   print "Hello : ", par
   return

import:

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

import module1[, module2[,... moduleN]

زمانی که مفسر با یک import مواجه می‌شود، اگر ماژول مورد نظر در مسیر جستجو وجود داشته باشد، مفسر ماژول مذکور را به برنامه اضافه می‌کند.

مسیر جستجو، لیستی از دایرکتوری‌هاست که مفسر قبل از وارد کردن هر ماژول، در آن‌ها جستجو می‌کند. با پیدا کردن ماژول در مسیر جستجو، مفسر ماژول را بارگذاری کرده و قابل استفاده در برنامه می‌سازد.
به عنوان مثال، برای وارد کردن ماژول support.py، باید دستور زیر را در بالای اسکریپت قرار دهید:

# Import module support
import support

# Now you can call defined function that module as follows
support.print_func("Sara")

وقتی کد بالا اجرا می‌شود، نتیجه زیر مشاهده خواهد شد:

Hello : Sara

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

from...import

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

from...import دارای ساختار زیر است:

from modname import name1[, name2[, ... nameN]]

به عنوان مثال، برای وارد کردن تابع فیبوناچی از ماژول fib، از دستور import  زیر استفاده می شود

from fib import fibonacci

 در مثال فوق تنها مورد fibonacci از ماژول fib به  ماژول آورده می‌شود و کل ماژول fib به فضای نام فعلی آورده نمی‌شود.
 

 *  from  ...  import 

همچنین، با استفاده از  *  from ... import، امکان آوردن تمام نام‌ها از یک ماژول به فضای نام فعلی وجود دارد.
استفاده از  *  from...import به صورت زیر است:

from modname import *

یافتن ماژول‌ها

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

1-ابتدا، در دایرکتوری فعلی جستجو می‌کند.

2-اگر ماژول در دایرکتوری فعلی پیدا نشود، به دنبال ماژول در دایرکتوری‌های متغیر PYTHONPATH که توسط ترمینال تعیین شده‌اند، می‌گردد.

3-اگر هنوز ماژول پیدا نشده باشد، در نهایت مسیر پیش‌فرض را بررسی می‌کند. به طور معمول در سیستم‌های UNIX، مسیر پیش‌فرض به /usr/local/lib/python/ اشاره دارد.

مسیر جستجوی ماژول‌ها در ماژول سیستم sys به عنوان متغیر sys.path ذخیره می‌شود. این متغیر sys.path شامل دایرکتوری فعلی، PYTHONPATH و مقادیر پیش‌فرض وابسته به نصب پایتون است.

متغیر PYTHONPATH

PYTHONPATH یک متغیر محیطی است که شامل یک لیست از دایرکتوری‌ها می باشد. نحوه نوشتن PYTHONPATH مشابه نحوه نوشتن متغیر پوشه ترمینال PATH است. به عبارت دیگر، PYTHONPATH به مسیرهایی اشاره دارد که مفسر پایتون در جستجوی ماژول‌ها از آن‌ها استفاده می‌کند.
 مثالی از یک PYTHONPATH نمونه از یک سیستم ویندوزی را مشاهده میکنید:

set PYTHONPATH = c:\python20\lib;

مثالی از  یک PYTHONPATH نمونه از یک سیستم UNIX را مشاهده میکنید:

set PYTHONPATH = /usr/local/lib/python

فضای نام و Scoping

متغیرها،نام‌هایی هستند که به انواع داده نگاشت می‌شوند. یک فضای نام، به عنوان یک دیکشنری از نام‌های متغیر (کلیدها) و شی‌های متناظر آن‌ها (مقادیر) عمل می‌کند.
یک دستور در پایتون می‌تواند به متغیرها در دو فضای نام محلی و سراسری دسترسی پیدا کند. اگر یک متغیر محلی و یک متغیر سراسری نام یکسان داشته باشند، متغیر محلی استفاده می شود و متغیر سراسری درنظر گرفته نمیشود.به عبارت دیگر، متغیر محلی با همان نام، نام متغیر سراسری را مسدود می‌کند و از دسترسی به مقدار سراسری متغیر جلوگیری می‌کند. این عملیات در پایتون به عنوان "سایه‌زنی" (Shadowing) شناخته می‌شود.

هر تابع دارای محیط محلی خود است. متدهای کلاس نیز قاعده Scoping را همانند توابع عادی اجرا می‌کنند.

در پایتون، تشخصی‌های خوبی در مورد اینکه متغیرها محلی یا سراسری هستند، انجام می گردد. پایتون این پیشفرض را دارد که هر متغیری که در یک تابع به آن مقداری نسبت داده شود، متغیر محلی است. به عبارت دیگر، اگر یک متغیر در داخل یک تابع تعریف شود و مقداری به آن اختصاص یابد، فرض می‌شود که این متغیر محلی تابع است و فضای نام آن تابع محدود به تابع خواهد بود. این پیشفرض‌ها در بسیاری از موارد همینگونه است. برای تغییر این موضوع در موارد خاصی می‌توان با استفاده از کلمه کلیدی global یا nonlocal نحوه Scoping متغیرها را تغییر داد

بنابراین، برای نسبت دادن مقدار به یک متغیر سراسری درون یک تابع، باید ابتدا از دستور global استفاده کنید.

 اصطلاح `global` در پایتون برای تعریف یک متغیر به عنوان یک متغیر سراسری استفاده می‌شود. با استفاده از این اصطلاح، شما به پایتون می‌گوید که نام متغیر مورد نظر در فضای نام سراسری قرار دارد و نیازی به تعریف مجدد آن در فضای نام محلی نیست.

وقتی یک متغیر را درون یک تابع تعریف می‌کنید و به آن مقدار اختصاص می‌دهید، پایتون ابتدا در فضای نام محلی تلاش می‌کند تا متغیر محلی با همان نام را پیدا کند. اگر پیدا نشود، به فضای نام سراسری پیش می‌رود و مقدار متغیر سراسری را به‌جای متغیر محلی استفاده می‌کند. اما اگر پیش از اختصاص مقدار به متغیر، دسترسی به متغیر محلی وجود داشته باشد، پایتون اجازه نمی‌دهد که آن متغیر محلی باشد و خطای `UnboundLocalError` را نمایش می‌دهد.

برای حل این مشکل، می‌توانید از کلمه کلیدی `global` استفاده کنید تا پایتون را مطلع کنید که متغیر به عنوان یک متغیر سراسری تعریف شده است و نباید به عنوان متغیر محلی استفاده شود. با حذف کامنت `global`، پایتون دیگر از فضای نام محلی استفاده نمی‌کند و به جای آن به فضای نام سراسری می‌رود و خطا برطرف می‌شود.

Money = 2000
def AddMoney():
   # Uncomment the following line to fix the code:
   # global Money
   Money = Money + 1

print(Money)
AddMoney()
print(Money)

تابع ()dir

 تابع داخلی `()dir` در پایتون یک لیست مرتب شده از رشته‌ها را برمی‌گرداند که حاوی نام‌هایی است که توسط یک ماژول تعریف شده‌اند. این تابع معمولاً برای بررسی محتوای یک ماژول و دیدن نام‌های تعریف شده در آن مورد استفاده قرار می‌گیرد.

به عبارت دیگر، `dir(module_name)` لیستی از نام‌ها (متغیرها، توابع، کلاس‌ها و ...) را که توسط ماژول `module_name` تعریف شده‌اند را برمی‌گرداند. این لیست معمولاً به صورت مرتب و الفبایی نمایش داده می‌شود. با استفاده از این تابع می‌توانید نام‌های موجود در یک ماژول را به‌دست آورده و از آن‌ها استفاده کنید.

 مثالی ساده:

# Import built-in module math
import math

content = dir(math)
print(content)

هنگام اجرای کد بالا، نتیجه زیر مشاهده خواهد شد:

['__doc__', '__file__', '__name__', 'acos', 'asin', 'atan', 
'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp', 
'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log',
'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 
'sqrt', 'tan', 'tanh']

در پایتون، متغیرهای رشته‌ای ویژه `__name__` و `__file__` به صورت پیش‌فرض در هر ماژول موجود هستند.

 `__name__`: این متغیر رشته‌ای نام ماژول را نشان می‌دهد. اگر ماژول مستقیماً اجرا شود (به عنوان برنامه اصلی)، مقدار `__name__` برابر با `"__main__"` خواهد بود. اما اگر ماژول از طریق  ماژول‌های دیگر وارد شود، مقدار `__name__` برابر با نام ماژول خواهد بود.

 `__file__`: این متغیر رشته‌ای نام فایلی را نشان می‌دهد که ماژول از آن بارگذاری شده است. این متغیر فقط زمانی مقداردهی می‌شود که ماژول از یک فایل بارگذاری شده باشد (یعنی نه از محیط تعاملی و نه از ماژول‌های دیگر به عنوان وابستگی). در غیر این صورت، مقدار `__file__` برابر با `None` خواهد بود.

توابع () globals و() locals

توابع `()globals` و `()locals` در پایتون به شما امکان می‌دهند که بر اساس محلی که از آن‌ها صدا زده شده‌اند، نام‌های موجود در فضای نام‌های سراسری و محلی را بدست آورید.

وقتی `()locals` از داخل یک تابع صدا زده می‌شود، همه نام‌های قابل دسترسی به صورت محلی در آن تابع به شکل یک دیکشنری برگردانده می‌شود.

همچنین، وقتی `()globals` از داخل یک تابع صدا زده می‌شود، همه نام‌های قابل دسترسی به صورت سراسری از آن تابع به شکل یک دیکشنری برگردانده می‌شود.

در نتیجه، نوع برگشتی هر دوی این توابع دیکشنری است و می‌توانید با استفاده از تابع `()keys` این دیکشنری‌ها را برای استخراج نام‌ها استفاده کنید. با این اطلاعات، شما می‌توانید به راحتی با نام‌های موجود در فضای نام‌های محلی و سراسری در برنامه‌های پایتون کار کنید.

تابع() reload

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

اگر نیاز مجدد برای اجرای کد بخش بالایی ماژول دارید، می‌توانید از تابع() reload استفاده کنید. تابع ()reload برای دوباره وارد کردن ماژولی که قبلاً وارد شده است، استفاده می‌شود. با این کار، کدها و تعریف‌ها در ماژول مجدداً اجرا و اعمال می‌شوند.

مهم است بدانید که تابع () reloadدر نسخه‌های جدید پایتون (بعد از نسخه 3.4) دیگر در بسته‌ی استاندارد پایتون وجود ندارد. به عنوان جایگزین می‌توانید از ماژول importlib و تابع ()importlib.reload استفاده کنید. این تابع نیز همان عملکرد ()reload را دارد و ماژول را مجدداً بارگذاری می‌کند.

نحو تابع () reload :

reload(module_name)

در این متن، module_name نام ماژولی را مشخص می‌کند که می‌خواهید مجدداً وارد کنید و نه خود رشته‌ای که نام ماژول را شامل می‌شود. برای مثال، اگر می‌خواهید ماژولی به نام "hello" را مجدداً وارد کنید، به صورت زیر عمل کنید:

reload(hello)

Packageدر پایتون

یک بسته (Package) در پایتون یک ساختار سلسله مراتبی از فایل‌ها و دایرکتوری‌ها است که یک محیط برنامه‌نویسی پایتون را تعریف می‌کند. این ساختار شامل ماژول‌ها، زیربسته‌هاو غیره است که به صورت سلسله مراتبی در داخل یک دایرکتوری اصلی (بسته اصلی) قرار می‌گیرند.

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

فرض کنید یک فایل به نام Pots.py در دایرکتوری Phone وجود دارد. این فایل دارای خط کد زیر میباشد:

def Pots():
   print("I'm Pots Phone")

به روش مشابه، ما دو فایل دیگر داریم که عملکردهای متفاوتی دارند -

  1. Phone/Isdn.py file دارای تاریع Isdn()
  2. Phone/G3.py file دارای تابع G3()

با ایجاد فایل init__.py__ در دایرکتوری Phone، آن دایرکتوری به عنوان یک بسته شناخته می‌شود و می‌توانید از توابع موجود در فایل‌های Isdn.py و G3.py استفاده کنید. محتوای فایل init__.py__ به صورت خالی می‌تواند باشد و یا می‌توانید در آن چند خط کد اجرایی مرتبط با بسته خودتان قرار دهید.

فرض کنید داریم:

فایل Isdn.py:

def Isdn():
    print("ISDN function in Isdn.py")

فایل G3.py:
 

def G3():
    print("G3 function in G3.py")

فایل __init__.py (می‌تواند خالی باشد):

# کد‌های دیگری که مرتبط با بسته Phone هستند

حالا می‌توانید از بسته Phone و توابع ()Isdn و ()G3 استفاده کنید:

# ایمپورت بسته Phone
import Phone

# استفاده از تابع Isdn
Phone.Isdn.Isdn()

# استفاده از تابع G3
Phone.G3.G3()

با اجرای کد بالا، خروجی زیر را خواهید داشت:

ISDN function in Isdn.py
G3 function in G3.py

توجه داشته باشید که نام بسته (دایرکتوری)، نام فایل init__.py__ نیز در ایمپورت بسته محسوب می‌شود. در مثال بالا، اگر فایل init__.py__ وجود نداشته باشد، ایمپورت باید به صورت زیر باشد:

import Phone.Isdn
import Phone.G3

زمانی که کد بالا اجرا می‌شود، نتیجه زیر را مشاهده خواهید کرد:

I'm Pots Phone
I'm 3G Phone
I'm ISDN Phone

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