7. دستورهای ساده¶
یک دستور ساده در یک خط منطقی جای میگیرد. چند دستور ساده ممکن است در یک خط بیایند و با نقطهویرگول از هم جدا شوند. سینتکس دستورات ساده به این صورت است:
simple_stmt:expression_stmt|assert_stmt|assignment_stmt|augmented_assignment_stmt|annotated_assignment_stmt|pass_stmt|del_stmt|return_stmt|yield_stmt|raise_stmt|break_stmt|continue_stmt|import_stmt|future_stmt|global_stmt|nonlocal_stmt|type_stmt
7.1. دستورهای عبارت¶
دستورهای عبارت (بیشتر بهصورت تعاملی) برای محاسبه و نوشتن یک مقدار، یا (معمولاً) برای فراخوانی یک رویه (تابعی که هیچ نتیجهی معناداری برنمیگرداند؛ در پایتون، رویهها مقدار None را برمیگردانند) استفاده میشوند. سایر کاربردهای دستورهای عبارت مجاز هستند و گاهی مفیدند. سینتکس یک دستور عبارت به این صورت است:
expression_stmt: starred_expression
یک دستور عبارتی، فهرست عبارتها را ارزیابی میکند (که ممکن است یک عبارت واحد باشد).
در حالت تعاملی، اگر مقدار None نباشد، با استفاده از تابع توکار repr() به یک رشته تبدیل میشود و رشته حاصل در یک خط جداگانه در خروجی استاندارد نوشته میشود (مگر اینکه نتیجه None باشد، تا فراخوانیهای رویه هیچ خروجی ایجاد نکنند.)
7.2. دستورهای انتساب¶
دستورهای انتساب برای (باز)مقیدسازی نامها به مقادیر و تغییر ویژگیها یا آیتمهای اشیاء تغییرپذیر استفاده میشوند:
assignment_stmt: (target_list"=")+ (starred_expression|yield_expression) target_list:target(","target)* [","] target:identifier| "(" [target_list] ")" | "[" [target_list] "]" |attributeref|subscription| "*"target
(برای تعاریف سینتکس attributeref و subscription به بخش اولیهها مراجعه کنید.)
یک دستور انتساب، فهرست عبارتها را ارزیابی میکند (به یاد داشته باشید که این میتواند یک عبارت واحد یا فهرستی جداشده با ویرگول باشد که دومی یک تاپل به دست میدهد) و تنها شیء حاصل را به هر یک از فهرستهای هدف، از چپ به راست، اختصاص میدهد.
انتساب بسته به شکل فهرست هدف بهصورت بازگشتی تعریف میشود. هنگامی که یک هدف بخشی از یک شیء تغییرپذیر باشد (ارجاع به ویژگی یا زیرنویسی)، شیء تغییرپذیر باید در نهایت انتساب را انجام دهد و درباره اعتبار آن تصمیم بگیرد، و ممکن است در صورت غیرقابلقبول بودن انتساب، استثنا پرتاب کند. قواعدی که انواع مختلف رعایت میکنند و استثناهایی که پرتاب میشوند، همراه با تعریف انواع شیء آمدهاند (بخش سلسلهمراتب انواع استاندارد را ببینید).
انتساب یک شیء به یک فهرست هدف، که بهاختیار در پرانتز یا کروشه قرار گرفته است، بهصورت بازگشتی بهشکل زیر تعریف میشود.
اگر فهرست هدف، یک هدف واحد بدون ویرگول پایانی باشد که بهاختیار داخل پرانتز قرار گرفته است، شیء به آن هدف انتساب میشود.
در غیر این صورت:
اگر فهرست هدف شامل یک هدف با پیشوند ستاره باشد که هدف «ستارهدار» نامیده میشود: شیء باید پیمایشپذیری باشد که تعداد آیتمهای آن حداقل برابر با تعداد هدفهای موجود در فهرست هدف، منهای یک، باشد. آیتمهای نخست پیمایشپذیر، از چپ به راست، به هدفهای پیش از هدف ستارهدار اختصاص داده میشوند. آیتمهای پایانی پیمایشپذیر به هدفهای پس از هدف ستارهدار اختصاص داده میشوند. سپس فهرستی از آیتمهای باقیمانده در پیمایشپذیر به هدف ستارهدار اختصاص داده میشود (این فهرست میتواند خالی باشد).
در غیر این صورت: شیء باید پیمایشپذیری باشد که همان تعداد آیتم را داشته باشد که هدفها در فهرست هدف وجود دارند، و آیتمها از چپ به راست، به هدفهای متناظر اختصاص داده میشوند.
انتساب یک شیء به یک هدف واحد، بهصورت بازگشتی به شکل زیر تعریف شده است.
اگر هدف یک شناسه (نام) باشد:
اگر نام در یک دستور
globalیاnonlocalدر بلوک کد فعلی وجود نداشته باشد: نام به شیء در فضای نام محلی فعلی پیوند داده میشود.در غیر این صورت: نام بهترتیب در فضای نام سراسری یا فضای نام بیرونی تعیینشده توسط
nonlocalبه شیء پیوند داده میشود.
اگر نام از قبل مقید شده باشد، دوباره مقید میشود. این ممکن است باعث شود شمار ارجاع شیءای که پیشتر به آن نام مقید شده بود به صفر برسد و در نتیجه، شیء آزاد شود و مخرب آن (اگر داشته باشد) فراخوانی شود.
اگر هدف یک ارجاع به ویژگی باشد: عبارت اصلی در ارجاع ارزیابی میشود. این عبارت باید شیئی با ویژگیهای قابل انتساب حاصل کند؛ در غیر این صورت،
TypeErrorپرتاب میشود. سپس از آن شیء خواسته میشود که شیء انتسابدادهشده را به ویژگی دادهشده انتساب دهد؛ اگر نتواند این انتساب را انجام دهد، یک استثنا پرتاب میکند (معمولاً اما نه لزوماًAttributeError).نکته: اگر شیء نمونهای از کلاس باشد و ارجاع به ویژگی در هر دو طرف عملگر انتساب رخ دهد، عبارت سمت راست،
a.xمیتواند به یک ویژگی نمونه یا (اگر ویژگی نمونه وجود نداشته باشد) به یک ویژگی کلاس دسترسی داشته باشد. هدف سمت چپa.xهمیشه بهعنوان یک ویژگی نمونه تنظیم میشود و در صورت لزوم ایجاد میگردد. بنابراین، دو مورد ازa.xلزوماً به یک ویژگی اشاره نمیکنند: اگر عبارت سمت راست به یک ویژگی کلاس اشاره کند، سمت چپ یک ویژگی نمونه جدید را بهعنوان هدف انتساب ایجاد میکند:class Cls: x = 3 # class variable inst = Cls() inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3
این توضیح لزوماً در مورد ویژگیهای توصیفگر، مانند پراپرتیهایی که با
@propertyایجاد شدهاند، صدق نمیکند.اگر هدف یک زیرنویسی (subscription) باشد: عبارت اصلیِ ارجاع ارزیابی میشود. سپس، عبارت زیرنویس (subscript) ارزیابی میشود. آنگاه متد
__setitem__()عبارت اصلی با دو آرگومان فراخوانی میشود: زیرنویس و شیء تخصیصیافته.معمولاً
__setitem__()روی اشیاء دنبالهای تغییرپذیر (مانند فهرستها) و اشیاء نگاشت (مانند دیکشنریها) تعریف میشود و بهصورت زیر رفتار میکند.اگر شیء اصلی یک دنبالهی تغییرپذیر (مانند یک فهرست) باشد، عبارت اندیسدهی باید یک عدد صحیح تولید کند. اگر این مقدار منفی باشد، طول دنباله به آن افزوده میشود. مقدار حاصل باید یک عدد صحیح نامنفی کوچکتر از طول دنباله باشد، و از دنباله خواسته میشود شیء مورد انتساب را به آیتم خود در آن اندیس اختصاص دهد. اگر اندیس خارج از محدوده باشد،
IndexErrorپرتاب میشود (انتساب به یک دنبالهی اندیسدهیشده نمیتواند آیتمهای جدیدی به یک فهرست اضافه کند).اگر شیء اصلی یک شیء نگاشت (مانند یک دیکشنری) باشد، زیرنویس باید نوعی سازگار با نوع کلید نگاشت داشته باشد، و سپس از نگاشت خواسته میشود یک جفت کلید/مقدار ایجاد کند که زیرنویس را به شیء انتسابدادهشده نگاشت میکند. این عمل میتواند یک جفت کلید/مقدار موجود با همان مقدار کلید را جایگزین کند یا یک جفت کلید/مقدار جدید درج کند (اگر هیچ کلیدی با همان مقدار وجود نداشته باشد).
اگر هدف یک اسلایس باشد: عبارت اصلی باید به یک شیء دنباله تغییرپذیر (مانند یک فهرست) ارزیابی شود. شیء انتسابیافته باید پیمایشپذیر باشد. کرانهای پایین و بالای اسلایس باید عدد صحیح باشند؛ اگر آنها
Noneباشند (یا وجود نداشته باشند)، مقادیر پیشفرض ۰ و طول دنباله هستند. اگر هر یک از کرانها منفی باشد، طول دنباله به آن افزوده میشود. کرانهای حاصل بهگونهای محدود میشوند که بین ۰ و طول دنباله (شامل هر دو) قرار گیرند. در نهایت، از شیء دنباله خواسته میشود که اسلایس را با آیتمهای دنباله انتسابیافته جایگزین کند. طول اسلایس ممکن است با طول دنباله انتسابیافته متفاوت باشد، و در نتیجه اگر دنباله هدف اجازه دهد، طول دنباله هدف تغییر میکند.
اگرچه تعریف انتساب دلالت بر این دارد که همپوشانیهای میان سمت چپ و سمت راست «همزمان» هستند (برای مثال a, b = b, a دو متغیر را جابهجا میکند)، اما همپوشانیهای درون مجموعهی متغیرهایی که به آنها انتساب داده میشود بهترتیب از چپ به راست رخ میدهند و گاهی موجب سردرگمی میشوند. برای مثال، برنامهی زیر [0, 2] را چاپ میکند:
x = [0, 1]
i = 0
i, x[i] = 1, 2 # i is updated, then x[i] is updated
print(x)
همچنین ملاحظه نمائید
- PEP 3132 - واگشایی گسترشیافتهی پیمایشپذیر
مشخصات قابلیت
*target.
7.2.1. دستورهای انتساب افزوده¶
انتساب افزایشی، ترکیبی از یک عملیات دودویی و یک دستور انتساب در یک دستور واحد است:
augmented_assignment_stmt:augtargetaugop(expression_list|yield_expression) augtarget:identifier|attributeref|subscriptionaugop: "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**=" | ">>=" | "<<=" | "&=" | "^=" | "|="
(برای تعاریف سینتکس سه نماد آخر، بخش اولیهها را ببینید.)
یک انتساب افزوده، هدف (که برخلاف دستورهای انتساب معمولی، نمیتواند واگشایی باشد) و فهرست عبارتها را ارزیابی میکند، عملیات دودویی متناسب با نوع انتساب را روی دو عملوند انجام میدهد و نتیجه را به هدف اولیه انتساب میدهد. هدف فقط یک بار ارزیابی میشود.
یک دستور انتساب افزایشی مانند x += 1 را میتوان بهصورت x = x + 1 بازنویسی کرد تا اثری مشابه، اما نه دقیقاً برابر، بهدست آید. در حالت افزایشی، x تنها یک بار ارزیابی میشود. همچنین، در صورت امکان، عملیات واقعی بهصورت درجا انجام میشود، به این معنا که بهجای ایجاد یک شیء جدید و اختصاص آن به هدف، شیء قدیمی تغییر مییابد.
برخلاف انتسابهای معمولی، انتسابهای افزوده سمت چپ را پیش از ارزیابی سمت راست ارزیابی میکنند. برای مثال، a[i] += f(x) ابتدا a[i] را جستوجو میکند، سپس f(x) را ارزیابی میکند و عمل جمع را انجام میدهد، و در نهایت، نتیجه را دوباره در a[i] مینویسد.
بهاستثنای انتساب به تاپلها و اهداف چندگانه در یک دستور، انتسابی که توسط دستورهای انتساب افزوده انجام میشود، به همان شیوهی انتسابهای عادی مدیریت میشود. به همین ترتیب، بهاستثنای رفتار احتمالی درجا، عملیات دودویی انجامشده توسط انتساب افزوده، همانند عملیاتهای دودویی عادی است.
برای اهدافی که ارجاع به ویژگی هستند، همان هشدار درباره ویژگیهای کلاس و نمونه همانند انتسابهای معمولی صدق میکند.
7.2.2. دستورهای انتساب حاشیهنویسیشده¶
انتساب حاشیهنویسی ترکیب یک حاشیهنویسی متغیر یا ویژگی و یک دستور انتساب اختیاری در یک دستور واحد است:
annotated_assignment_stmt:augtarget":"expression["=" (starred_expression|yield_expression)]
تفاوت آن با انتساب معمولی در این است که تنها یک هدف مجاز است.
هدف انتساب در صورتی «ساده» در نظر گرفته میشود که تنها شامل یک نام واحد باشد و آن نام در پرانتز قرار نداشته باشد. برای اهداف انتساب ساده، اگر در محدوده کلاس یا ماژول باشند، حاشیهنویسیها در یک محدوده حاشیهنویسی که بهصورت تنبل ارزیابی میشود جمعآوری میشوند. میتوان حاشیهنویسیها را با استفاده از ویژگی __annotations__ یک کلاس یا ماژول، یا با استفاده از امکانات ماژول annotationlib ارزیابی کرد.
اگر هدف انتساب ساده نباشد (یک ویژگی، گره اندیسدهی، یا نام داخل پرانتز)، حاشیهنویسی هرگز ارزیابی نمیشود.
اگر نامی در محدوده تابع حاشیهنویسی شده باشد، این نام برای آن محدوده محلی است. حاشیهنویسیها هرگز ارزیابی نمیشوند و در محدودههای تابع ذخیره نمیشوند.
اگر سمت راست وجود داشته باشد، یک انتساب حاشیهنویسیشده، انتساب واقعی را چنان انجام میدهد که گویی حاشیهنویسی وجود ندارد. اگر سمت راست برای یک هدف عبارتی وجود نداشته باشد، مفسر هدف را بهجز آخرین فراخوانی __setitem__() یا __setattr__() ارزیابی میکند.
همچنین ملاحظه نمائید
- PEP 526 - سینتکس حاشیهنویسی متغیرها
پیشنهادی که سینتکسی برای حاشیهنویسی انواع متغیرها (از جمله متغیرهای کلاس و متغیرهای نمونه) افزود، به جای بیان آنها از طریق کامنتها.
- PEP 484 - راهنماییهای نوع
پیشنهادی که ماژول
typingرا برای فراهم کردن یک سینتکس استاندارد برای حاشیهنویسیهای نوع افزود تا در ابزارهای تحلیل ایستا و IDEها قابل استفاده باشد.
تغییر یافته در نسخهی 3.8: اکنون انتسابهای حاشیهنویسیشده (annotated assignments) اجازه میدهند در سمت راست همان عباراتی به کار روند که در انتسابهای معمولی به کار میروند. پیش از این، برخی عبارات (مانند عبارات تاپلی بدون پرانتز) باعث خطای سینتکسی میشدند.
تغییر یافته در نسخهی 3.14: اکنون حاشیهنویسیها بهصورت تنبل در یک محدودهی حاشیهنویسی جداگانه ارزیابی میشوند. اگر هدف انتساب ساده نباشد، حاشیهنویسیها هرگز ارزیابی نمیشوند.
7.3. دستور assert¶
دستورهای assert روشی مناسب برای درج ادعاهای اشکالزدایی در یک برنامه هستند:
assert_stmt: "assert"expression[","expression]
شکل ساده، assert expression، معادل است با
if __debug__:
if not expression: raise AssertionError
صورت گسترده، assert expression1, expression2، معادل است با
if __debug__:
if not expression1: raise AssertionError(expression2)
این معادلها فرض میکنند که __debug__ و AssertionError به متغیرهای توکار با همان نامها اشاره دارند. در پیادهسازی فعلی، متغیر توکار __debug__ در شرایط عادی True است و هنگام درخواست بهینهسازی (گزینه خط فرمان -O) False است. تولیدگر کد فعلی، هنگامی که بهینهسازی در زمان کامپایل درخواست شود، هیچ کدی برای یک دستور assert تولید نمیکند. توجه داشته باشید که نیازی به گنجاندن کد منبع عبارت شکستخورده در پیام خطا نیست؛ این کد بهعنوان بخشی از ردگیری پشته نمایش داده خواهد شد.
انتساب به __debug__ غیرمجاز است. مقدار متغیر توکار هنگام شروع مفسر تعیین میشود.
7.4. دستور pass¶
pass_stmt: "pass"
pass یک عملیات پوچ است — هنگامی که اجرا میشود، هیچ اتفاقی رخ نمیدهد. این بهعنوان یک جاینگهدار مفید است، هنگامی که یک دستور از نظر سینتکسی لازم است اما نیازی به اجرای هیچ کدی نیست، برای مثال:
def f(arg): pass # a function that does nothing (yet)
class C: pass # a class with no methods (yet)
7.5. دستور del¶
del_stmt: "del" target_list
حذف بهصورت بازگشتی بسیار مشابه نحوهی تعریف انتساب، تعریف شده است. بهجای بیان آن با تمام جزئیات، در اینجا چند نکته آمده است.
حذف یک فهرست هدف، بهصورت بازگشتی هر هدف را از چپ به راست حذف میکند.
حذف یک نام، بسته به اینکه نام در یک دستور global در همان بلوک کد آمده باشد، پیوند آن نام را از فضای نام محلی یا سراسری برمیدارد. تلاش برای حذف یک نام بدون پیوند، استثنای NameError را پرتاب میکند.
حذف ارجاعهای ویژگی و زیرنویسیها (subscriptions) به شیء اصلی درگیر محول میشود؛ حذف یک اسلایس بهطور کلی معادل انتساب یک اسلایس خالی از نوع صحیح است (اما حتی این مورد نیز توسط شیء اسلایسشده تعیین میشود).
تغییر یافته در نسخهی 3.2: پیشتر، حذف یک نام از فضای نام محلی در صورتی که آن نام بهعنوان متغیر آزاد در یک بلوک تودرتو ظاهر میشد، غیرمجاز بود.
7.6. دستور return¶
return_stmt: "return" [expression_list]
return فقط میتواند از نظر سینتکسی بهصورت تودرتو درون یک تعریف تابع ظاهر شود، نه درون یک تعریف کلاس تودرتو.
اگر فهرست عبارت موجود باشد، ارزیابی میشود، در غیر این صورت None جایگزین میشود.
return فراخوانی تابع جاری را با فهرست عبارت (یا None) بهعنوان مقدار بازگشتی ترک میکند.
هنگامی که return کنترل را از یک دستور try با بند finally خارج میکند، آن بند finally پیش از خروج واقعی از تابع اجرا میشود.
در یک تابع تولیدگر، دستور return نشان میدهد که تولیدگر تمام شده است و باعث پرتاب StopIteration میشود. مقدار برگرداندهشده (در صورت وجود) بهعنوان آرگومان برای ساخت StopIteration استفاده میشود و به ویژگی StopIteration.value تبدیل میشود.
در یک تابع تولیدگر ناهمگام، یک دستور return خالی نشان میدهد که تولیدگر ناهمگام به پایان رسیده است و باعث پرتاب StopAsyncIteration میشود. یک دستور return غیرخالی در یک تابع تولیدگر ناهمگام خطای سینتکس است.
7.7. دستور yield¶
yield_stmt: yield_expression
یک دستور yield از نظر معنایی معادل یک عبارت yield است. میتوان از دستور yield برای حذف پرانتزهایی استفاده کرد که در غیر این صورت در دستور معادل با عبارت yield لازم بودند. برای مثال، دستورات yield
yield <expr>
yield from <expr>
معادل دستورهای عبارت yield هستند
(yield <expr>)
(yield from <expr>)
عبارات و دستورات yield فقط هنگام تعریف یک تابع تولیدگر به کار میروند و فقط در بدنه تابع تولیدگر استفاده میشوند. استفاده از yield در تعریف تابع، کافی است تا آن تعریف بهجای یک تابع معمولی، یک تابع تولیدگر بسازد.
برای جزئیات کامل معناشناسی کلیدواژهی yield، به بخش عبارتهای yield مراجعه کنید.
7.8. دستور raise¶
raise_stmt: "raise" [expression["from"expression]]
اگر هیچ عبارتی وجود نداشته باشد، raise استثنایی را که در حال حاضر رسیدگی میشود دوباره پرتاب میکند، که به آن استثنای فعال نیز گفته میشود. اگر در حال حاضر استثنای فعالی وجود نداشته باشد، یک استثنای RuntimeError پرتاب میشود که نشان میدهد این یک خطا است.
در غیر این صورت، raise اولین عبارت را بهعنوان شیء استثنا ارزیابی میکند. این مقدار باید یا یک زیرکلاس از BaseException یا یک نمونه از آن باشد. اگر یک کلاس باشد، نمونهی استثنا در صورت نیاز با نمونهسازی آن کلاس بدون آرگومان به دست میآید.
type استثنا، کلاس نمونهی استثنا است و value خود نمونه است.
یک شیء ردگیری پشته بهطور معمول بهصورت خودکار هنگامی که یک استثنا پرتاب میشود ایجاد میشود و بهعنوان ویژگی __traceback__ به آن متصل میشود. شما میتوانید یک استثنا ایجاد کنید و ردگیری پشتهی خود را در یک مرحله با استفاده از متد with_traceback() استثنا تنظیم کنید (که همان نمونهی استثنا را برمیگرداند، در حالی که ردگیری پشتهی آن روی آرگومانش تنظیم شده است)، به این صورت:
raise Exception("foo occurred").with_traceback(tracebackobj)
بند from برای زنجیرهسازی استثناها استفاده میشود: در صورت ارائه، دومین عبارت باید یک کلاس یا نمونه استثنای دیگر باشد. اگر عبارت دوم یک نمونه استثنا باشد، آن نمونه بهعنوان ویژگی __cause__ (که قابل نوشتن است) به استثنای پرتابشده ضمیمه میشود. اگر عبارت یک کلاس استثنا باشد، آن کلاس نمونهسازی میشود و نمونه استثنای حاصل بهعنوان ویژگی __cause__ به استثنای پرتابشده ضمیمه میشود. اگر استثنای پرتابشده مدیریت نشود، هر دو استثنا چاپ میشوند:
>>> try:
... print(1 / 0)
... except Exception as exc:
... raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
print(1 / 0)
~~^~~
ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
raise RuntimeError("Something bad happened") from exc
RuntimeError: Something bad happened
اگر هنگامی که یک استثنا از قبل در حال رسیدگی است، استثنای جدیدی پرتاب شود، سازوکار مشابهی بهصورت ضمنی عمل میکند. یک استثنا ممکن است زمانی رسیدگی شود که از یک بند except یا finally، یا یک دستور with استفاده شود. سپس استثنای پیشین بهعنوان ویژگی __context__ به استثنای جدید پیوست میشود:
>>> try:
... print(1 / 0)
... except:
... raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
print(1 / 0)
~~^~~
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
raise RuntimeError("Something bad happened")
RuntimeError: Something bad happened
میتوان زنجیرهسازی استثناها را بهصراحت با مشخص کردن None در بند from سرکوب کرد:
>>> try:
... print(1 / 0)
... except:
... raise RuntimeError("Something bad happened") from None
...
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened
اطلاعات بیشتر دربارهی استثناها را میتوانید در بخش استثناها بیابید، و اطلاعات مربوط به مدیریت استثناها در بخش دستور try آمده است.
تغییر یافته در نسخهی 3.3: None اکنون بهعنوان Y در raise X from Y مجاز است.
ویژگی __suppress_context__ برای جلوگیری از نمایش خودکار زمینهی استثنا افزوده شد.
تغییر یافته در نسخهی 3.11: اگر ردگیری پشتهی استثنای فعال در یک بند except تغییر داده شود، یک دستور raise بعدی استثنا را با ردگیری پشتهی تغییریافته دوباره پرتاب میکند. پیش از این، استثنا با ردگیری پشتهای که در زمان گرفته شدن داشت دوباره پرتاب میشد.
7.9. دستور break¶
break_stmt: "break"
break فقط میتواند از نظر سینتکسی بهصورت تودرتو در یک حلقهی for یا while قرار گیرد، اما نه بهصورت تودرتو در تعریف تابع یا کلاس درون آن حلقه.
این دستور نزدیکترین حلقهی دربرگیرنده را خاتمه میدهد و اگر حلقه دارای بند اختیاری else باشد، از آن میگذرد.
اگر یک حلقهی for با break خاتمه یابد، هدف کنترل حلقه مقدار فعلی خود را حفظ میکند.
هنگامی که break کنترل را از یک دستور try دارای بند finally خارج میکند، آن بند finally پیش از خروج واقعی از حلقه اجرا میشود.
7.10. دستور continue¶
continue_stmt: "continue"
continue تنها میتواند از نظر سینتکسی درون یک حلقهی for یا while قرار گیرد، اما نه درون تعریف یک تابع یا کلاس در داخل آن حلقه. این دستور به چرخهی بعدی نزدیکترین حلقهی دربرگیرنده ادامه میدهد.
هنگامی که continue کنترل را از یک دستور try با بند finally خارج میکند، آن بند finally پیش از آغاز واقعی دور بعدی حلقه اجرا میشود.
7.11. دستور import¶
import_stmt: "import"module["as"identifier] (","module["as"identifier])* | "from"relative_module"import"identifier["as"identifier] (","identifier["as"identifier])* | "from"relative_module"import" "("identifier["as"identifier] (","identifier["as"identifier])* [","] ")" | "from"relative_module"import" "*" module: (identifier".")*identifierrelative_module: "."*module| "."+
دستور ایمپورت پایه (بدون بند from) در دو مرحله اجرا میشود:
یافتن یک ماژول، بارگذاری و مقداردهی اولیهی آن در صورت لزوم
یک یا چند نام را در فضای نام جاریِ محدودهای که دستور
importدر آن رخ میدهد تعریف میکند، دقیقاً همانگونه که یک دستور انتساب این کار را انجام میدهد (شامل معناشناسیglobalوnonlocal).
هنگامی که دستور شامل چندین بند (جداشده با ویرگول) باشد، دو مرحله برای هر بند بهطور جداگانه انجام میشوند، درست گویی که بندها به دستورات ایمپورت جداگانه تفکیک شده باشند.
جزئیات مرحله اول، یعنی یافتن و بارگذاری ماژولها، با جزئیات بیشتر در بخش مربوط به سیستم ایمپورت توضیح داده شده است، که همچنین انواع مختلف بستهها و ماژولهای قابل ایمپورت، و نیز همه قلابهایی (hooks) را که میتوان از آنها برای سفارشیسازی سیستم ایمپورت استفاده کرد، توصیف میکند. توجه داشته باشید که شکستها در این مرحله ممکن است نشاندهنده این باشند که ماژول یافت نشد، یا اینکه هنگام مقداردهی اولیه ماژول، که شامل اجرای کد ماژول نیز میشود، خطایی رخ داده است.
اگر ماژول درخواستشده با موفقیت بازیابی شود، در فضای نام محلی به یکی از سه روش در دسترس قرار خواهد گرفت:
اگر پس از نام ماژول
asبیاید، نامی که پس ازasمیآید، مستقیماً به ماژول ایمپورتشده متصل میشود.اگر نام دیگری مشخص نشده باشد و ماژولی که ایمپورت میشود یک ماژول سطح بالا باشد، نام ماژول در فضای نام محلی بهعنوان ارجاعی به ماژول ایمپورتشده مقید میشود
اگر ماژولی که ایمپورت میشود یک ماژول سطح بالا نباشد، آنگاه نام بسته سطح بالایی که آن ماژول را شامل میشود، در فضای نام محلی بهعنوان ارجاعی به بسته سطح بالا مقید میشود. برای دسترسی به ماژول ایمپورتشده باید بهجای دسترسی مستقیم، از نام کامل آن استفاده کنید
قالب from از فرآیند کمی پیچیدهتری استفاده میکند:
یافتن ماژول مشخصشده در بند
from، بارگذاری و مقداردهی اولیهی آن در صورت نیاز؛برای هر یک از شناسههایی که در بندهای
importمشخص شدهاند:بررسی کنید که آیا ماژول ایمپورتشده ویژگیای با آن نام دارد یا خیر
در غیر این صورت، سعی کنید یک زیرماژول با آن نام را ایمپورت کنید و سپس ماژول ایمپورتشده را دوباره برای آن ویژگی بررسی کنید
اگر ویژگی پیدا نشود،
ImportErrorپرتاب میشود.در غیر این صورت، ارجاعی به آن مقدار در فضای نام فعلی ذخیره میشود؛ اگر بند
asوجود داشته باشد، از نامِ موجود در آن استفاده میشود، در غیر این صورت از نام ویژگی استفاده میشود
مثالها:
import foo # foo imported and bound locally
import foo.bar.baz # foo, foo.bar, and foo.bar.baz imported, foo bound locally
import foo.bar.baz as fbb # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as fbb
from foo.bar import baz # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as baz
from foo import attr # foo imported and foo.attr bound as attr
اگر فهرست شناسهها با یک ستاره ('*') جایگزین شود، همه نامهای عمومی تعریفشده در ماژول، در فضای نام محلیِ محدودهای که دستور import در آن رخ میدهد، مقید میشوند.
نامهای عمومی تعریفشده توسط یک ماژول، با بررسی فضای نام ماژول برای یافتن متغیری به نام __all__ تعیین میشوند؛ در صورت تعریفشدن، باید دنبالهای از رشتهها باشد؛ این رشتهها نامهایی تعریفشده یا ایمپورتشده توسط آن ماژول هستند. نامهای حاوی نویسههای غیر ASCII باید در normalization form NFKC باشند؛ برای جزئیات، نویسههای غیر ASCII در نامها را ببینید. همهی نامهای دادهشده در __all__ عمومی در نظر گرفته میشوند و باید وجود داشته باشند. اگر __all__ تعریفنشده باشد، مجموعهی نامهای عمومی شامل همهی نامهایی است که در فضای نام ماژول یافت میشوند و با نویسهی زیرخط ('_') آغاز نمیشوند. __all__ باید شامل کل API عمومی باشد. هدف آن جلوگیری از اکسپورت شدن تصادفی آیتمهایی است که بخشی از API نیستند (مانند ماژولهای کتابخانهای که ایمپورتشدهاند و درون ماژول استفادهشدهاند).
شکل ایمپورت وایلدکارد --- from module import * --- فقط در سطح ماژول مجاز است. تلاش برای استفاده از آن در تعریف کلاس یا تابع باعث پرتاب یک SyntaxError میشود.
هنگام مشخص کردن ماژولی که باید ایمپورت شود، لازم نیست نام مطلق ماژول را مشخص کنید. هنگامی که یک ماژول یا بسته درون بسته دیگری قرار دارد، میتوان بدون ذکر نام بسته، یک ایمپورت نسبی در همان بسته سطح بالا انجام داد. با استفاده از نقطههای ابتدایی در ماژول یا بسته مشخصشده پس از from، میتوانید مشخص کنید که تا چه سطحی در سلسلهمراتب بسته جاری به بالا پیمایش کنید، بدون آنکه نامهای دقیق را ذکر کنید. ۱ نقطه ابتدایی به معنای بسته جاری است؛ یعنی جایی که ماژول ایمپورتکننده در آن قرار دارد. ۲ نقطه یعنی ۱ سطح بسته بالاتر. ۳ نقطه یعنی ۲ سطح بالاتر، و غیره. بنابراین اگر from . import mod را از یک ماژول در بسته pkg اجرا کنید، در نهایت pkg.mod را ایمپورت خواهید کرد. اگر from ..subpkg2 import mod را از درون pkg.subpkg1 اجرا کنید، pkg.subpkg2.mod را ایمپورت خواهید کرد. مشخصات ایمپورتهای نسبی در بخش ایمپورتهای نسبی بسته آمده است.
importlib.import_module() برای پشتیبانی از برنامههایی ارائه شده است که ماژولهایی را که باید بارگذاری شوند، بهصورت پویا تعیین میکنند.
یک رویداد حسابرسی import را با آرگومانهای module، filename، sys.path، sys.meta_path و sys.path_hooks پرتاب میکند.
7.11.1. دستورهای آینده¶
یک future statement دایرکتیوی به کامپایلر است که یک ماژول خاص باید با استفاده از سینتکس یا معناشناسیای کامپایل شود که در یک نسخه آینده مشخص از پایتون در دسترس خواهد بود، نسخهای که در آن قابلیت استاندارد میشود.
دستور future برای تسهیل مهاجرت به نسخههای آیندهی پایتون که تغییرات ناسازگاری را در زبان معرفی میکنند، در نظر گرفته شده است. این دستور استفاده از قابلیتهای جدید را بهازای هر ماژول، پیش از انتشاری که آن قابلیت استاندارد میشود، ممکن میسازد.
future_stmt: "from" "__future__" "import"feature["as"identifier] (","feature["as"identifier])* | "from" "__future__" "import" "("feature["as"identifier] (","feature["as"identifier])* [","] ")" feature:identifier
یک دستور آینده باید نزدیک ابتدای ماژول قرار بگیرد. تنها سطرهایی که میتوانند پیش از یک دستور آینده ظاهر شوند، عبارتاند از:
رشته مستند ماژول (در صورت وجود)،
کامنتها،
سطرهای خالی، و
دستورهای future دیگر.
تنها قابلیتی که نیازمند استفاده از دستور future است، annotations است (به PEP 563 مراجعه کنید).
تمام قابلیتهای تاریخی که با دستور future فعال میشوند، همچنان توسط پایتون 3 شناسایی میشوند. این فهرست شامل absolute_import، division، generators، generator_stop، unicode_literals، print_function، nested_scopes و with_statement است. همهی آنها زائد هستند، زیرا همیشه فعالاند و فقط برای سازگاری با نسخههای قدیمی نگه داشته شدهاند.
یک دستور future در زمان کامپایل شناخته میشود و بهصورت ویژه با آن رفتار میشود: تغییرات در معناشناسی ساختارهای اصلی اغلب با تولید کد متفاوت پیادهسازی میشوند. حتی ممکن است یک قابلیت جدید، سینتکس ناسازگار جدیدی را معرفی کند (مانند یک کلیدواژه رزروشده جدید)، که در این صورت کامپایلر ممکن است نیاز داشته باشد ماژول را بهشکل متفاوتی تجزیه کند. چنین تصمیماتی را نمیتوان تا رانتایم به تعویق انداخت.
برای هر انتشار مشخص، کامپایلر میداند کدامیک از نامهای ویژگی تعریف شدهاند، و اگر یک دستور future شامل ویژگیای باشد که برای کامپایلر شناختهشده نیست، خطای زمان کامپایل پرتاب میکند.
معناشناسی مستقیم رانتایم همانند هر دستور ایمپورت است: یک ماژول استاندارد به نام __future__ وجود دارد که بعداً توضیح داده شده است و این ماژول در زمان اجرای دستور future به روش معمول ایمپورت میشود.
معناشناسی قابلتوجه رانتایم به ویژگی خاصی بستگی دارد که با دستور future فعال میشود.
توجه داشته باشید که هیچ چیز خاصی دربارهی این دستور وجود ندارد:
import __future__ [as name]
این یک دستور آینده نیست؛ بلکه یک دستور ایمپورت معمولی بدون معنای خاص یا محدودیتهای سینتکسی خاصی است.
کدی که با فراخوانی توابع توکار exec() و compile() در ماژول M حاوی یک دستور آینده (future statement) کامپایل میشود، بهطور پیشفرض از سینتکس یا معناشناسی جدید مرتبط با دستور آینده استفاده میکند. این موضوع را میتوان با آرگومانهای اختیاری compile() کنترل کرد --- برای جزئیات، مستندات آن تابع را ببینید.
یک دستور آینده که در اعلان مفسر تعاملی وارد شود، برای ادامهی نشست مفسر اعمال خواهد شد. اگر مفسری با گزینهی -i آغاز شود، نام اسکریپتی برای اجرا به آن داده شود و آن اسکریپت شامل یک دستور آینده باشد، آن دستور در نشست تعاملی که پس از اجرای اسکریپت آغاز میشود، معتبر خواهد بود.
همچنین ملاحظه نمائید
- PEP 236 - بازگشت به __future__
پیشنهاد اولیه برای سازوکار __future__.
7.12. دستور global¶
global_stmt: "global"identifier(","identifier)*
دستور global باعث میشود شناسههای فهرستشده بهعنوان سراسری تفسیر شوند. بدون global، انتساب به یک متغیر سراسری غیرممکن خواهد بود، اگرچه متغیرهای آزاد ممکن است بدون اینکه سراسری اعلام شوند، به سراسریها ارجاع دهند.
دستور global بر کل محدوده فعلی (ماژول، بدنه تابع یا تعریف کلاس) اعمال میشود. اگر از متغیری پیش از اعلام سراسری آن در محدوده استفاده شود یا به آن انتساب داده شود، یک SyntaxError پرتاب میشود.
در سطح ماژول، تمام متغیرها سراسری هستند، بنابراین یک دستور global بیاثر است. با این حال، هنوز هم نباید از متغیرها پیش از اعلام آنها بهصورت global استفاده کرد یا به آنها انتساب داد. این الزام در خط فرمان تعاملی (REPL) سختگیری کمتری دارد.
یادداشت برنامهنویس: global دایرکتیو برای پارسر است. این دستور فقط به کدی اعمال میشود که همزمان با دستور global تجزیه میشود. بهویژه، دستور global موجود در یک رشته یا شیء کدی که به تابع توکار exec() داده میشود، بر بلوک کد حاوی فراخوانی تابع تأثیر نمیگذارد، و کد موجود در چنین رشتهای تحت تأثیر دستورات global در کد حاوی فراخوانی تابع قرار نمیگیرد. همین موضوع در مورد توابع eval() و compile() نیز صدق میکند.
7.13. دستور nonlocal¶
nonlocal_stmt: "nonlocal"identifier(","identifier)*
هنگامی که تعریف یک تابع یا کلاس بهصورت تودرتو (محصورشده) درون تعاریف توابع دیگر قرار میگیرد، محدودههای غیرمحلی آن، محدودههای محلی توابع دربرگیرنده هستند. دستور nonlocal باعث میشود شناسههای فهرستشده به نامهایی ارجاع دهند که پیشتر در محدودههای غیرمحلی متصل شدهاند. این دستور به کد محصورشده اجازه میدهد چنین شناسههای غیرمحلی را دوباره متصل کند. اگر نامی در بیش از یک محدوده غیرمحلی متصل شده باشد، نزدیکترین اتصال استفاده میشود. اگر نامی در هیچ محدوده غیرمحلی متصل نشده باشد، یا اگر محدوده غیرمحلی وجود نداشته باشد، یک SyntaxError پرتاب میشود.
دستور nonlocal به تمام محدودهی بدنهی یک تابع یا کلاس اعمال میشود. اگر یک متغیر پیش از اعلام nonlocal آن در محدوده استفاده شود یا به آن مقدار اختصاص داده شود، یک SyntaxError پرتاب میشود.
یادداشت برنامهنویس: nonlocal یک دایرکتیو برای پارسر است و فقط به کدی اعمال میشود که همراه با آن تجزیه شده باشد. یادداشت مربوط به دستور global را ببینید.
7.14. دستور type¶
type_stmt: 'type'identifier[type_params] "="expression
دستور type یک نام مستعار نوع اعلام میکند، که نمونهای از typing.TypeAliasType است.
برای مثال، دستور زیر یک نام مستعار نوع ایجاد میکند:
type Point = tuple[float, float]
این کد تقریباً معادل است با:
annotation-def VALUE_OF_Point():
return tuple[float, float]
Point = typing.TypeAliasType("Point", VALUE_OF_Point())
annotation-def یک محدوده حاشیهنویسی (annotation scope) را نشان میدهد، که بیشتر مانند یک تابع رفتار میکند، اما چند تفاوت کوچک دارد.
مقدار نام مستعار نوع در محدوده حاشیهنویسی (annotation scope) ارزیابی میشود. این مقدار در زمان ایجاد نام مستعار نوع ارزیابی نمیشود، بلکه تنها زمانی ارزیابی میشود که به مقدار از طریق ویژگی __value__ نام مستعار نوع دسترسی پیدا شود (به ارزیابی تنبل مراجعه کنید). این امر به نام مستعار نوع اجازه میدهد که به نامهایی که هنوز تعریف نشدهاند ارجاع دهد.
نامهای مستعار نوع میتوانند با افزودن یک فهرست پارامترهای نوع پس از نام، عام شوند. برای اطلاعات بیشتر، نامهای مستعار نوع عام را ببینید.
type یک کلیدواژه نرم است.
اضافه شده در نسخهی 3.12.
همچنین ملاحظه نمائید
- PEP 695 - سینتکس پارامتر نوع
دستور
typeو سینتکس کلاسها و توابع عام معرفی شدند.