سلام دوستان ...در قسمت قبل آموزش پایتون مفاهیم زیر را یاد دادیم
با ادامه آموزش پایتون همراه ما باشید.
پکیج (package) روشی برای ساخت فضای نام (namespace) ماژول پایتون با استفاده از " نام ماژول های نقطه گذاری شده" است.
برای مثال، نام ماژول A.B تعیین کننده یک زیر ماژول به نام B در پکیجی به نام A است. همانند کاربرد ماژول ها که نویسنده ماژول های مختلف را از نگرانی درباره نام متغیر های سراسری هم دیگر می رهاند، استفاده از نام ماژول های نقطه گذاری شده نیز نویسنده پکیج های چند ماژولی مانند NumPy و Pillow را از نگرانی درباره نام ماژول های یکدیگر می رهاند.
فرض کنید می خواهید برای مدیریت یکپارچه فایل ها و داده های صوتی، مجموعه ای از ماژول ها (یک پکیج) را طراحی کنید. فایل های صوتی فرمت های بسیار مختلفی دارند (که معمولا توسط دنباله خود شناخته می شوند مانند .wav , .aiff , .au) ، بنابراین ممکن است مجبور شوید یک مجموعه در حال رشد از ماژول ها را برای تبدیل فرمت های مختلف به هم ایجاد و نگهداری کنید. همچنین ممکن است بخواهید عملیات مختلف زیادی را روی داده های صوتی اعمال کنید (مانند ترکیب کردن، افزودن پژواک، اعمال یک تابع برابر کننده، ساخت یک اثر stereo مصنوعی)، بنابراین شما جریانی از ماژول هایی که هیچگاه تمام نمیشود را برای انجام این عملیات خواهید نوشت. در اینجا یک ساختار محتمل برای پکیج شما وجود دارد (در غالب سیستم فایل سلسله مراتبی بیان شده است).
sound/ Top-level package
__init__.py Initialize the sound package
formats/ Subpackage for file format conversions
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/ Subpackage for sound effects
__init__.py
echo.py
surround.py
reverse.py
...
filters/ Subpackage for filters
__init__.py
equalizer.py
vocoder.py
karaoke.py
...
هنگامی که پکیج را وارد (import) می کنید، پایتون برای پیدا کردن زیر دایرکتوری پکیج، درون دایرکتوری های روی sys.path را جستجو می کند. برای این که پایتون دیکشنری های حاوی فایل را به عنوان پکیج بشناسد، به فایل های __init__.py نیاز دارد.
این کار مانع از این می شود تا دیکشنری هایی با نام های متداول مانند string ، به طور غیر عمد ماژول های معتبری که بعدا در مسیر جستجوی ماژول قرار میگیرند را پنهان کنند. در ساده ترین حالت، __init__.py می تواند فقط یک فایل خالی باشد، اما همچنین می تواند کد مقدار دهی اولیه (اولیه سازی) برای پکیج را اجرا کند یا متغیر __all__ variable که بعدا توضیح داده می شود را تنظیم کند. کاربران پکیج می توانند ماژول های مجزا را از پکیج وارد کنند، برای مثال:
import sound.effects.echo
این دستور زیر ماژول sound.effects.echo را بار گذری می کند، و باید به نام کامل آن ارجاع داده شود.
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
روش جایگزین برای وارد کردن زیر ماژول به این صورت است:
from sound.effects import echo
این دستور همچنین زیر ماژول echo را نیز بار گذاری می کند، و آن را بدون پسوند پکیج خود، در دسترس قرار می دهد، بنابراین میتوان به صورت زیر از آن استفاده کرد:
echo.echofilter(input, output, delay=0.7, atten=4)
علاوه بر آن می توان تابع یا متغیر دلخواه را مستقیما وارد کرد:
from sound.effects.echo import echofilter
دوباره، این دستور زیر ماژول echo را بار گذاری می کند، اما تابع echofilter() آن را مستقیما در دسترس قرار می دهد.
echofilter(input, output, delay=0.7, atten=4)
توجه داشته باشید در هنگام استفاده از from package import item ، آیتم می تواند یک زیر ماژول (یا زیر پکیج) از پکیج باشد، یا هر نام دیگری که در پکیج تعریف شده باشد، مانند یک تابع، کلاس یا متغیر. عبارت import در ابتدا بررسی می کند که آیا آیتم در پکیج تعریف شده است، اگر تعریف نشده باشد، فرض می کند که آن یک ماژول است و برای بارگذاری آن اقدام می کند.
اگر در پیدا کردن آن شکست بخورد، استثنای ImportError رخ می دهد. در مقابل، هنگامی که از نحوه نگارش import item.subitem.subsubitem استفاده می کنید، همه آیتم ها به جز مورد آخر باید یک پکیج باشند. آیتم آخر می تواند یک ماژول یا یک پکیج باشد اما نمیتواند یک کلاس یا تابع یا متغیر تعریف شده در آیتم های قبلی باشد.
حال اگر کاربر from sound.effects import * را بنویسد چه اتفاقی می افتد؟
در شرایط ایده آل می توان امیدوار بود که به طریقی به سیستم فایل برود و زیر ماژول های حاضر در پکیج را پیدا کند و همه آنها را وارد کند. این کار می تواند زمان زیادی طول بکشد و وارد کردن زیر ماژول ها می تواند اثرات جانبی ناخواسته ای داشته باشد که باید تنها زمانی که زیر ماژول صریحا وارد می شود اتفاق افتد. تنها راه حل این است که نویسنده پکیج یک اندیس صریح از پکیج را ارائه کند. عبارت import از قرارداد زیر استفاده می کند:
اگر کد __init__.py یک پکیج، یک لیست به نام __all__ را تعریف کند، فرض می شود که لیستی از نام ماژول هایی است که در صورت مواجهه با from package import * ، باید وارد شود.
در زمانی که نسخه جدیدی از پکیج ارائه می شود، به روز نگه داشتن این لیست به عهده نویسنده پکیج است. همچنین ممکن است نویسنده پکیج تصمیم بگیرد در صورتی که کاربردی برای وارد کردن * از پکیج آنها نبینند، از آن پشتیبانی نکند. برای مثال، فایل sound/effects/__init__.py می تواند شامل کد زیر باشد:
__all__ = ["echo", "surround", "reverse"]
این به این معنی است که from sound.effects import * سه زیر ماژول نام برده شده از پکیج sound را وارد می کند. اگر __all__ تعریف نشده باشد، عبارت from sound.effects import * تمامی زیر ماژول های پکیج sound.effects را درون فضای نام فعلی وارد نمی کند.
این عبارت فقط تضمین می کند که پکیج sound.effects وارد شده است (احتمالا اجرای هر کد اولیه سازی در __init__.py) و سپس هر نام تعریف شده در پکیج را وارد می کند. این شامل هر نام (و زیر ماژول هایی که صریحا بارگذاری شده اند) تعریف شده توسط __init__.py می باشد. همچنین شامل هر زیر ماژولی از پکیج است که توسط عبارت import قبلی صریحا بارگذاری شده باشد. این کد را در نظر بگیرید:
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
در این مثال، ماژول های echo و surround در فضای نام فعلی وارد شده اند، زیرا زمانی که عبارت from...import اجرا می شود، آنها در پکیج sound.effects تعریف شده اند. (همچنین زمانی که __all__ تعریف شده است نیز عمل می کند.) با وجود اینکه ماژول های خاصی برای فقط صادر کردن(export) نام هایی که در هنگام استفاده از import * از الگوهای خاصی پیروی می کنند طراحی شده است، این، همچنان عملکرد بد در تولید کد در نظر گرفته می شود. به یاد داشته باشید، هیچ مشکلی در استفاده از from package import specific_submodule وجود ندارد.
در واقع، این نحوه نگارش توصیه شده است مگر اینکه ماژول های وارد شده نیاز به استفاده از زیر ماژول هایی با نام یکسان از پکیج های مختلف داشته باشند.
زمانی که پکیج ها درون زیر پکیج ها ساخته می شوند ( مانند پکیج sound در مثال)، می توانید از واردات مستقل (absolute imports) برای ارجاع به زیر ماژول های پکیج های هم خانواده استفاده کنید.
برای مثال، اگر ماژول sound.filters.vocoder نیاز به استفاده از ماژول echo در پکیج sound.effects داشته باشد، می تواند از from sound.effects import echo استفاده کند. همچنین می توانید واردات وابسته (relative imports) را در قالب from module import name از عبارات واردات بنویسید. این واردات از نقاط راهنما برای بیان پکیج های فعلی و والد درگیر در واردات وابسته استفاده می کند. برای مثال ممکن است از ماژول surround استفاده کنید:
from . import echo
from .. import formats
from ..filters import equalizer
توجه داشته باشید که واردات وابسته مبتنی بر نام ماژول فعلی هستند. از آنجایی که نام ماژول اصلی همیشه "__main__" است، ماژول هایی که برای استفاده به عنوان ماژول اصلی برنامه پایتون در نظر گرفته می شوند، همیشه باید از واردات مستقل استفاده کنند.
پکیج ها از یک ویژگی خاص دیگر به نام __path__ نیز پشتیبانی می کنند. این به گونه ای مقدار دهی اولیه شده است که یک لیست شامل نام دایرکتوری باشد که _init__.py مربوط به پکیج را قبل از اینکه کد درون آن فایل اجرا شود، نگه می دارد.
. این متغیر قابل تغییر است، این کار روی جستجو های آینده در زمینه ماژول ها و زیر پکیج های موجود در پکیج تاثیر می گذارد. هر چند که این ویژگی اغلب مورد نیاز نیست، از آن می توان برای توسعه مجموعه ماژول های موجود در یک پکیج استفاده کرد.
توجه !
در واقع تعریف توابع عباراتی هستند که اجرا می شوند. اجرای تعریف یک تابع در سطح ماژول، وارد نام تابع در جدول نماد سراسری ماژول می شود.
چندین روش برای نمایش خروجی یک برنامه وجود دارد. می توان داده را به صورت قابل خواندن برای انسان چاپ کرد، یا برای استفاده در آینده درون یک فایل نوشت. در این بخش درباره برخی از روش ها صحبت خواهیم کرد.
تا اینجا با دو روش نوشتن مقادیر آشنا شده ایم: عبارات اصطلاحی و تابع print() . ( روش سوم استفاده از متد write() اشیای فایل است. به فایل خروجی استاندارد به عنوان sys.stdout می توان ارجاع داد. برای اطلاعات بیشتر در این زمینه بخش مرجع کتابخانه (Library Reference) را ببینید.) شما اغلب خواهان کنترل بیشتری روی قالب خروجی خود هستید تا اینکه فقط خروجی را به صورت مقادیر جدا شده با فاصله چاپ کنید.
در این جا چندین روش برای قالب بندی خروجی ارائه شده است.
>>> year = 2016
>>> event = 'Referendum'
>>> f'Results of the {year} {event}'
'Results of the 2016 Referendum'
متد str.format() مربوط به رشته ها نیاز به تلاش دستی بیشتری دارد. شما همچنان برای تعیین این که کجا یک متغیر جایگزین خواهد شد و نیز برای ارائه دستورات قالب بندی با جزییات از { و } استفاده خواهید کرد، اما شما همچنین باید اطلاعات را به صورت قالب بندی شده ارائه کنید.
>>> yes_votes = 42_572_654
>>> no_votes = 43_132_495
>>> percentage = yes_votes / (yes_votes + no_votes)
>>> '{:-9} YES votes {:2.2%}'.format(yes_votes, percentage)
' 42572654 YES votes 49.67%'
زمانی که به خروجی تفننی احتیاج ندارید و فقط یک نمایش سریع از برخی از متغیر ها برای اهداف اشکال زدایی می خواهید، می توانید با استفاده از توابع repr() یا str() هر مقداری را به رشته تبدیل کنید.
تابع str() برای بازگرداندن نمایش مقادیری که نسبتا برای انسان قابل خواندن هستند در نظر گرفته شده است، در حالی که repr() برای تولید نمایشی که توسط مفسر قابل خواندن باشد در نظر گرفته شده است (یا اگر هیچ نگارش برابری نباشد، یک SyntaxError را اعمال می کند).
برای اشیایی که هیچ نمایش خاصی برای مصرف انسان ندارند، str() مقدار مشابه repr() را باز می گرداند. مقادیر بسیاری، مانند اعداد و ساختارهایی مانند لیست ها و دیکشنری ها، در زمان استفاده از هر یک از توابع ذکر شده، نمایش یکسانی دارند. رشته ها به طور خاص، دو نمایش متمایز دارند. تعدادی مثال:
>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'
>>> repr(s)
"'Hello, world.'"
>>> str(1/7)
'0.14285714285714285'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
>>> print(s)
The value of x is 32.5, and y is 40000...
>>> # The repr() of a string adds string quotes and backslashes:
... hello = 'hello, world\n'
>>> hellos = repr(hello)
>>> print(hellos)
'hello, world\n'
>>> # The argument to repr() may be any Python object:
... repr((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"
ماژول string در بر دارنده کلاس template است که روشی دیگر برای جایگزینی مقادیر با رشته ها را پیشنهاد می کند، استفاده از فضا نگهدار هایی مانند $x و جایگزینی آنها با مقادیری از یک دیکشنری، اما کنترل کمتری نسبت به قالب بندی ارائه می کند.
حروف رشته قالب بندی شده در زبان پایتون
حروف رشته قالب بندی شده(به اختصار f-strings) به شما این امکان را می دهد تا با استفاده از پیشوند سازی یک رشته با f یا F و نوشتن عبارات به صورت {expression} مقادیر عبارات پایتون را درون یک رشته اضافه کنید.
. یک تشخیص دهنده قالب اختیاری می تواند عبارت را دنبال کند. این مورد، کنترل بیشتری را روی چگونگی قالب بندی مقادیر فراهم می کند. مثال زیر عدد π را تا سه رقم بعد از اعشار گرد می کند.
>>> import math
>>> print(f'The value of pi is approximately {math.pi:.3f}.')
The value of pi is approximately 3.142.
پاس دادن یک عدد صحیح بعد از ':' باعث می شود آن مکان به اندازه حداقل تعداد کاراکتر عریض شود. این برای ترسیم ستون ها مفید است.
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
... print(f'{name:10} ==> {phone:10d}')
...
Sjoerd ==> 4127
Jack ==> 4098
Dcab ==> 7678
از سایر اصلاح کننده ها برای تبدیل مقدار، پیش از قالب بندی می توان استفاده کرد. '!a' ، ascii() را اعمال می کند. '!s' ، str() را اعمال می کند و '!r' ، repr() را اعمال می کند.
>>> animals = 'eels'
>>> print(f'My hovercraft is full of {animals}.')
My hovercraft is full of eels.
>>> print(f'My hovercraft is full of {animals!r}.')
My hovercraft is full of 'eels'.
کاربرد اولیه متد str.format() به صورت زیر است:
>>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
We are the knights who say "Ni!"
براکت ها ({}) و کاراکتر های درون آنها (فیلدهای فرمت) توسط اشیای پاس داده شده به متد str.format() جایگزین می شوند. از اعداد درون براکت ها می توان برای ارجاع به مکان شی پاس داده شده به متد str.format() استفاده کرد.
>>> print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
>>> print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam
اگر از آرگومان های کلیدی در متد str.format() استفاده شده باشد، مقادیر آنها با استفاده از نام آرگومان، به آنها ارجاع داده می شود.
>>> print('This {food} is {adjective}.'.format(
... food='spam', adjective='absolutely horrible'))
This spam is absolutely horrible
آرگومان های مکانی و کلمه کلیدی می توانند به صورت دلخواه ترکیب شوند.
>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
other='Georg'))
The story of Bill, Manfred, and Georg.
اگر یک رشته قالب بندی واقعا بلندی دارید که نمی خواهید آن را تقسیم کنید، خوب است در صورت توان متغیر ها را به جای مکان بر اساس نام برای قالب بندی ارجاع دهید. این کار به سادگی با پاس دادن دیکشنری (dict) و استفاده از براکت های [] برای دسترسی به کلید ها انجام می شود.
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
... 'Dcab: {0[Dcab]:d}'.format(table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678
همچنین می توان با پاس دادن جدول به عنوان آرگومان های کلمه کلیدی با نماد ** ، این کار را انجام داد.
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678
این امر به خصوص در ترکیب با تابع داخلی vars() مفید است، که یک دیکشنری شامل همه متغیر های محلی را باز می گرداند. به عنوان یک مثال، خطوط زیر یک مجموعه مرتب و هم راستا از ستون هایی از اعداد صحیح و مربع (توان 2) و مکعب (توان 3) آن ها را تولید می کند.
>>> for x in range(1, 11):
... print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
...
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
در اینجا همان جدول مربع ها و مکعب ها را می بینید که به صورت دستی قالب بندی شده است:
>>> for x in range(1, 11):
... print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
... # Note use of 'end' on previous line
... print(repr(x*x*x).rjust(4))
...
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
(توجه داشته باشید که فاصله موجود بین ستون ها با استفاده از روش عملکرد print() اضافه شده است. این تابع همیشه بین آرگومان های خود فاصله اضافه می کند.)
متد str.rjust() مربوط به اشیای رشته، یک رشته را در یک فیلد با عرض داده شده از سمت راست تنظیم می کند. این تنظیمات با اعمال فاصله از سمت چپ توسط عمل لایه بندی(padding) انجام می شود.
متد های مشابه str.ljust() و str.center() نیز وجود دارند. این متدها هیچ چیزی نمی نویسند، آنها فقط یک رشته جدید را باز می گردانند. اگر رشته ورودی زیادی بلند باشد، آنها رشته را کوتاه نمی کنند، اما آن را بدون تغییر باز می گردانند.
این طرح خروجی ستون ها را به هم خواهد ریخت اما معمولا بهتر از این است که درباره مقدار دروغ بگویید. ( اگر واقعا کوتاه شدن را می خواهید، همیشه می توانید عملگر slice را اضافه کنید، مثل x.ljust(n)[:n]) یک متد دیگر به نام str.zfill() وجود دارد که یک رشته عددی را با صفر از سمت چپ لایه بندی می کند. این متد علامت ها جمع و تفریق را می فهمد.
>>> '12'.zfill(5)
'00012'
>>> '-3.14'.zfill(7)
'-003.14'
>>> '3.14159265359'.zfill(5)
'3.14159265359'
از عملگر % نیز می توان برای قالب بندی رشته استفاده کرد. این عملگر آرگومان سمت چپ را مانند یک رشته قالب بندی sprintf()-style تفسیر می کند تا به آرگومان سمت راست اعمال شود. سپس رشته حاصل شده از عملیات قالب بندی را باز می گرداند. برای مثال:
>>> import math
>>> print('The value of pi is approximately %5.3f.' % math.pi)
The value of pi is approximately 3.142.
آموزش پایتون ادامه دارد.