6. عبارات¶
این فصل معنای عناصر عبارتها در پایتون را توضیح میدهد.
یادداشتهای سینتکس: در این فصل و فصلهای پس از آن، از نمادگذاری دستور زبان برای توصیف سینتکس استفاده خواهد شد، نه برای تحلیل واژگانی.
هنگامی که (یکی از جایگزینهای) یک قاعدهی سینتکس به شکل زیر باشد:
name: othername
و هیچ معنایی ارائه نشده است، معنای این شکل از name همان معنای othername است.
6.1. تبدیلات حسابی¶
هرگاه در توضیح یک عملگر حسابی در زیر از عبارت «آرگومانهای عددی به یک نوع حقیقی مشترک تبدیل میشوند» استفاده شده باشد، این بدان معناست که پیادهسازی عملگر برای انواع عددی توکار، همانطور که در بخش انواع عددی مستندات کتابخانه استاندارد توضیح داده شده است، کار میکند.
برخی قواعد اضافی برای برخی عملگرها و عملوندهای غیرعددی اعمال میشوند (برای مثال، یک رشته بهعنوان آرگومان سمت چپ عملگر %). افزونهها باید رفتار تبدیل خود را تعریف کنند.
6.2. اتمها¶
اتمها بنیادیترین عناصر عبارتها هستند. سادهترین اتمها نامها یا مقادیر لفظی هستند. صورتهایی که در پرانتز، کروشه یا آکولاد محصور شدهاند نیز از نظر نحوی در دسته اتمها قرار میگیرند.
بهطور رسمی، سینتکس اتمها عبارت است از:
atom: | 'True' | 'False' | 'None' | '...' |identifier|literal|enclosureenclosure: |parenth_form|list_display|dict_display|set_display|generator_expression|yield_atom
6.2.1. ثابتهای توکار¶
کلیدواژههای True، False و None نامهای ثابتهای توکار هستند. توکن ... نام ثابت Ellipsis است.
ارزیابی این اتمها مقدار متناظر را به دست میدهد.
توجه
چند ثابت توکار دیگر نیز بهعنوان متغیرهای سراسری در دسترس هستند، اما تنها مواردی که در اینجا ذکر شدهاند کلیدواژهها هستند. بهویژه، این نامها را نمیتوان دوباره مقداردهی کرد یا بهعنوان ویژگی استفاده کرد:
>>> False = 123
File "<input>", line 1
False = 123
^^^^^
SyntaxError: cannot assign to False
6.2.2. شناسهها (نامها)¶
یک شناسه که بهعنوان یک اتم (atom) ظاهر میشود، یک نام است. بخش نامها (شناسهها و کلیدواژهها) را برای تعریف واژگانی و بخش نامگذاری و مقیدسازی را برای مستندات نامگذاری و پیوند ببینید.
هنگامی که نام به یک شیء مقید شده باشد، ارزیابی اتم، آن شیء را حاصل میکند. هنگامی که نامی مقید نشده باشد، تلاش برای ارزیابی آن، استثنای NameError را پرتاب میکند.
6.2.2.1. تغییر نام خصوصی (private name mangling)¶
هرگاه شناسهای که در متن تعریف یک کلاس آمده باشد با ۲ یا چند نویسه زیرخط آغاز شود و به ۲ یا چند زیرخط ختم نشود، یک نام خصوصی <private name> برای آن کلاس محسوب میشود.
همچنین ملاحظه نمائید
دقیقتر اینکه، نامهای خصوصی پیش از تولید کد برای آنها به شکل طولانیتری تبدیل میشوند. اگر نام تبدیلشده طولانیتر از ۲۵۵ نویسه باشد، ممکن است کوتاهسازی (truncation) تعریفشده توسط پیادهسازی رخ دهد.
این تبدیل مستقل از زمینهی نحویای است که شناسه در آن استفاده میشود، اما تنها شناسههای خصوصی زیر تغییر نام داده میشوند:
هر نامی که بهعنوان نام متغیری استفاده شود که به آن مقدار انتساب داده میشود یا خوانده میشود، یا هر نامی از یک ویژگی که مورد دسترسی قرار میگیرد.
با این حال، ویژگی
__name__در توابع، کلاسها و نامهای مستعار نوع تودرتو تغییر نام نمییابد.نام ماژولهای ایمپورتشده، برای مثال
__spamدرimport __spam. اگر ماژول بخشی از یک بسته باشد (یعنی نام آن شامل نقطه باشد)، نام دستکاری نمیشود، برای مثال__fooدرimport __foo.barدستکاری نمیشود.نام یک عضو ایمپورتشده، مثلاً
__fدرfrom spam import __f.
قاعده تبدیل بهصورت زیر تعریف شده است:
نام کلاس، پس از حذف زیرسطرهای آغازین و افزودن یک زیرخط در ابتدا، در جلوی شناسه قرار میگیرد؛ برای مثال، شناسهی
__spamکه در کلاسی با نامFoo،_Fooیا__Fooآمده باشد، به_Foo__spamتبدیل میشود.اگر نام کلاس فقط از زیرخط تشکیل شده باشد، تبدیل همانی است؛ برای مثال، شناسهی
__spamکه در کلاسی با نام_یا__آمده است، بدون تغییر باقی میماند.
6.2.3. مقادیر لفظی¶
لفظی <literal> نمایشی متنی از یک مقدار است. پایتون از مقادیر لفظی عددی، رشتهای و بایتی پشتیبانی میکند. افاسترینگها و رشتههای قالبی بهعنوان مقادیر لفظی رشتهای در نظر گرفته میشوند.
مقادیر لفظی عددی از یک توکن NUMBER تشکیل شدهاند که یک عدد صحیح، عدد ممیز شناور یا عدد موهومی را مشخص میکند. برای جزئیات، بخش مقادیر لفظی عددی را در مستندات تحلیل واژگانی ببینید.
مقادیر لفظی رشته و بایت ممکن است از چندین توکن تشکیل شده باشند. برای جزئیات، بخش الحاق رشتههای لفظی را ببینید.
توجه داشته باشید که اعداد منفی و مختلط، مانند -3 یا 3+4.2j، از نظر سینتکسی لفظی نیستند، بلکه عملیات حسابی یکعملوندی یا دوعملوندی هستند که شامل عملگر - یا + میشوند.
ارزیابی یک لفظی، شیءای از نوع دادهشده (int، float، complex، str، bytes، یا Template) با مقدار دادهشده را به دست میدهد. در مورد مقادیر لفظی ممیز شناور و موهومی، ممکن است مقدار تقریبی باشد.
دستور زبان صوری برای مقادیر لفظی چنین است:
literal:strings|NUMBER
6.2.3.1. مقادیر لفظی و هویت شیء¶
همهی مقادیر لفظی با انواع دادهی تغییرناپذیر متناظر هستند، و از این رو، هویت شیء کماهمیتتر از مقدار آن است. ارزیابیهای متعدد مقادیر لفظیی با مقدار یکسان (چه همان محل در متن برنامه و چه محلی دیگر) ممکن است همان شیء یا شیء متفاوتی با همان مقدار را به دست آورند.
جزئیات پیادهسازی CPython
برای مثال، در CPython، اعداد صحیح کوچک با مقدار یکسان، به یک شیء یکسان ارزیابی میشوند:
>>> x = 7
>>> y = 7
>>> x is y
True
با این حال، اعداد صحیح بزرگ به اشیاء متفاوتی ارزیابی میشوند:
>>> x = 123456789
>>> y = 123456789
>>> x is y
False
این رفتار ممکن است در نسخههای آینده CPython تغییر کند. بهویژه، مرز بین اعداد صحیح «کوچک» و «بزرگ» پیشتر تغییر کرده است.
CPython هنگامی که مقادیر لفظی را با استفاده از is مقایسه میکنید، یک SyntaxWarning نشان میدهد:
>>> x = 7
>>> x is 7
<input>:1: SyntaxWarning: "is" with 'int' literal. Did you mean "=="?
True
برای اطلاعات بیشتر، چه زمانی میتوانم به آزمونهای هویت با عملگر is اتکا کنم؟ را ببینید.
رشتههای الگو تغییرناپذیر هستند، اما ممکن است به اشیای تغییرپذیر بهعنوان مقادیر Interpolation ارجاع دهند. برای اهداف این بخش، دو تیاسترینگ «مقدار یکسان» دارند اگر هم ساختار آنها و هم هویت مقادیرشان مطابقت داشته باشد.
در حال حاضر، هر ارزیابی از یک رشتهی قالب به یک شیء متفاوت منجر میشود.
6.2.3.2. الحاق رشتههای لفظی¶
مقادیر لفظی مجاور رشته یا بایت، که ممکن است از قواعد متفاوتی برای علامت نقلقول استفاده کنند، مجاز هستند و معنای آنها همان معنای الحاق آنها است:
>>> "hello" 'world'
"helloworld"
این قابلیت در سطح سینتکس تعریف شده است، بنابراین فقط با مقادیر لفظی کار میکند. برای الحاق عبارات رشتهای در رانتایم، میتوان از عملگر '+' استفاده کرد:
>>> greeting = "Hello"
>>> space = " "
>>> name = "Blaise"
>>> print(greeting + space + name) # not: print(greeting space name)
Hello Blaise
در الحاق لفظی میتوان آزادانه رشتههای خام، رشتههای سهنقلقولی و مقادیر لفظی رشتهای قالببندیشده را با هم ترکیب کرد. برای مثال:
>>> "Hello" r', ' f"{name}!"
"Hello, Blaise!"
میتوان از این قابلیت برای کاهش تعداد بکاسلشهای مورد نیاز، تقسیم راحت رشتههای طولانی در سطرهای طولانی، یا حتی افزودن کامنت به بخشهایی از رشتهها استفاده کرد. برای مثال:
re.compile("[A-Za-z_]" # letter or underscore
"[A-Za-z0-9_]*" # letter, digit or underscore
)
با این حال، مقادیر لفظی بایت فقط میتوانند با دیگر مقادیر لفظی بایت ترکیب شوند؛ نه با مقادیر لفظی رشته از هیچ نوعی. همچنین، مقادیر لفظی رشته قالب فقط میتوانند با دیگر مقادیر لفظی رشته قالب ترکیب شوند:
>>> t"Hello" t"{name}!"
Template(strings=('Hello', '!'), interpolations=(...))
بهطور رسمی:
strings: (STRING|fstring)+ |tstring+
6.2.4. قالبهای پرانتزدار¶
شکل پرانتزدار، یک فهرست عبارت اختیاری است که در پرانتز محصور شده است:
parenth_form: "(" [starred_expression] ")"
یک فهرست عبارت پرانتزبندیشده، هر آنچه را که آن فهرست عبارت برمیگرداند، برمیگرداند: اگر فهرست دستکم شامل یک ویرگول باشد، یک تاپل برمیگرداند؛ در غیر این صورت، عبارت واحدی را برمیگرداند که فهرست عبارت را تشکیل میدهد.
یک جفت پرانتز خالی، یک شیء تاپل خالی را حاصل میکند. از آنجا که تاپلها تغییرناپذیرند، همان قواعد مربوط به مقادیر لفظی اعمال میشود (یعنی ممکن است دو رخداد از تاپل خالی، شیء یکسانی را حاصل دهند یا ندهند).
توجه داشته باشید که تاپلها با پرانتزها تشکیل نمیشوند، بلکه با استفاده از کاما تشکیل میشوند. استثنا، تاپل خالی است که برای آن پرانتزها الزامی هستند — اجازه دادن به «هیچ» بدون پرانتز در عبارتها باعث ایجاد ابهام میشود و اجازه میدهد خطاهای تایپی رایج بدون شناسایی باقی بمانند.
6.2.5. نمایش فهرستها، مجموعهها و دیکشنریها¶
برای ساختن فهرست، مجموعه یا دیکشنری، پایتون سینتکس خاصی به نام «نمایشها» (displays) فراهم میکند که هر کدام دو گونه دارند:
یا محتویات ظرف بهصورت صریح فهرست میشوند، یا
آنها از طریق مجموعهای از دستورهای حلقه و فیلتر کردن، که به آن comprehension گفته میشود، محاسبه میشوند.
عناصر نحوی مشترک برای درکها عبارتند از:
comprehension:assignment_expressioncomp_forcomp_for: ["async"] "for"target_list"in"or_test[comp_iter] comp_iter:comp_for|comp_ifcomp_if: "if"or_test[comp_iter]
این درک از یک عبارت واحد تشکیل شده است که پس از آن حداقل ۱ بند for و ۰ یا چند بند for یا if قرار میگیرد. در این حالت، عناصر ظرف جدید آنهایی هستند که با در نظر گرفتن هر یک از بندهای for یا if بهعنوان یک بلوک، تودرتو شدن آنها از چپ به راست، و ارزیابی عبارت برای تولید یک عنصر هر بار که به داخلیترین بلوک میرسید، تولید میشوند.
با این حال، بهجز عبارت پیمایشپذیر در چپترین بند for، درک در یک محدودهی تودرتوی ضمنی جداگانه اجرا میشود. این امر تضمین میکند که نامهایی که در فهرست هدف به آنها انتساب داده میشود، به محدودهی دربرگیرنده «نشت» نمیکنند.
عبارت پیمایشپذیر در چپترین بند for مستقیماً در محدوده دربرگیرنده ارزیابی میشود و سپس بهعنوان آرگومان به محدوده تودرتوی ضمنی ارسال میشود. بندهای for بعدی و هر شرط فیلتر در چپترین بند for نمیتوانند در محدوده دربرگیرنده ارزیابی شوند، زیرا ممکن است به مقادیر بهدستآمده از چپترین پیمایشپذیر وابسته باشند. برای مثال: [x*y for x in range(10) for y in range(x, x+10)].
برای اطمینان از اینکه درک همیشه به ظرفی از نوع مناسب منجر میشود، عبارتهای yield و yield from در محدودهی تودرتوی ضمنی ممنوع هستند.
از پایتون 3.6، در یک تابع async def، میتوان از یک بند async for برای تکرار بر روی یک asynchronous iterator استفاده کرد. یک درک در یک تابع async def میتواند شامل یک بند for یا async for پس از عبارت آغازین باشد، میتواند شامل بندهای for یا async for اضافی باشد، و همچنین میتواند از عبارتهای await استفاده کند.
اگر یک درک شامل بندهای async for باشد، یا شامل عبارتهای await یا دیگر درکهای ناهمگام در هر جایی بهجز عبارت پیمایشپذیر در چپترین بند for باشد، به آن درک ناهمگام <asynchronous comprehension> گفته میشود. یک درک ناهمگام ممکن است اجرای تابع همروالی که در آن ظاهر میشود را معلق کند. همچنین PEP 530 را ببینید.
اضافه شده در نسخهی 3.6: درکهای ناهمگام معرفی شدند.
تغییر یافته در نسخهی 3.8: yield و yield from در محدودهی تودرتوی ضمنی ممنوع است.
تغییر یافته در نسخهی 3.11: درکهای ناهمگام اکنون در داخل درکها در توابع ناهمگام مجاز هستند. درکهای بیرونی بهطور ضمنی ناهمگام میشوند.
6.2.6. نمایشهای فهرست¶
نمایش فهرست، دنبالهای از عبارتها است که ممکن است خالی باشد و درون کروشه قرار دارد:
list_display: "[" [flexible_expression_list|comprehension] "]"
یک نمایش فهرست، یک شیء فهرست جدید حاصل میکند که محتوای آن توسط یک فهرست از عبارتها یا یک درک فهرستی مشخص میشود. هنگامی که یک فهرست از عبارتهای جداشده با کاما ارائه شود، عناصر آن از چپ به راست ارزیابی میشوند و با همان ترتیب در شیء فهرست قرار میگیرند. هنگامی که یک درک فهرستی ارائه شود، فهرست از عناصر حاصل از آن درک ساخته میشود.
6.2.7. نمایشهای مجموعه¶
نمایش مجموعه با آکولادها مشخص میشود و به دلیل نبود علامت دونقطه برای جدا کردن کلیدها و مقدارها، از نمایشهای دیکشنری قابل تشخیص است:
set_display: "{" (flexible_expression_list|comprehension) "}"
یک نمایش مجموعه، یک شیء مجموعهی تغییرپذیر جدید ایجاد میکند که محتوای آن یا با دنبالهای از عبارتها یا با یک درک مشخص میشود. هنگامی که یک فهرست جداشده با کاما از عبارتها ارائه شود، عناصر آن از چپ به راست ارزیابی میشوند و به شیء مجموعه افزوده میشوند. هنگامی که یک درک ارائه شود، مجموعه از عناصر حاصل از آن درک ساخته میشود.
یک مجموعه خالی را نمیتوان با {} ساخت؛ این لفظی یک دیکشنری خالی میسازد.
6.2.8. نمایشهای دیکشنری¶
نمایش دیکشنری دنبالهای از آیتمهای دیکشنری (جفتهای کلید/مقدار) است که ممکن است خالی باشد و در آکولاد محصور شده است:
dict_display: "{" [dict_item_list|dict_comprehension] "}" dict_item_list:dict_item(","dict_item)* [","] dict_item:expression":"expression| "**"or_exprdict_comprehension:expression":"expressioncomp_for
یک نمایش دیکشنری، یک شیء دیکشنری جدید ایجاد میکند.
اگر دنبالهای از آیتمهای دیکشنری که با کاما از هم جدا شدهاند داده شود، آنها از چپ به راست ارزیابی میشوند تا ورودیهای دیکشنری را تعریف کنند: هر شیء کلید بهعنوان کلیدی در دیکشنری برای ذخیره مقدار متناظر استفاده میشود. این بدان معناست که شما میتوانید یک کلید را چندین بار در فهرست آیتمهای دیکشنری مشخص کنید و مقدار دیکشنری نهایی برای آن کلید، آخرین مقدار دادهشده خواهد بود.
نماد دو ستاره ** نشاندهنده واگشایی دیکشنری <dictionary unpacking> است. عملوند آن باید یک نگاشت باشد. هر آیتم از نگاشت به دیکشنری جدید اضافه میشود. مقادیر بعدی جایگزین مقادیری میشوند که از پیش توسط آیتمهای دیکشنری پیشین و واگشاییهای دیکشنری پیشین تعیین شدهاند.
اضافه شده در نسخهی 3.5: واگشایی در نمایشهای دیکشنری، که در ابتدا در PEP 448 پیشنهاد شده بود.
درک دیکشنری، برخلاف درک فهرستی و درک مجموعه، به دو عبارت نیاز دارد که با یک دونقط از هم جدا شدهاند و پس از آنها بندهای معمول «for» و «if» میآیند. هنگامی که درک اجرا میشود، عناصر کلید و مقدار حاصل به ترتیبی که تولید میشوند، در دیکشنری جدید درج میشوند.
محدودیتهای مربوط به نوع مقادیر کلید، پیشتر در بخش سلسلهمراتب انواع استاندارد فهرست شدهاند. (بهطور خلاصه، نوع کلید باید hashable باشد که همهی شیءهای تغییرپذیر را مستثنا میکند.) برخورد میان کلیدهای تکراری تشخیص داده نمیشود؛ آخرین مقداری که برای یک مقدار کلید مشخص ذخیره شده است (یعنی مقداری که از نظر متنی در نمایش، سمت راستتر قرار دارد) معتبر است.
تغییر یافته در نسخهی 3.8: پیش از پایتون 3.8، در درک دیکشنری، ترتیب ارزیابی کلید و مقدار بهخوبی تعریفنشده بود. در CPython، مقدار پیش از کلید ارزیابی میشد. از 3.8 به بعد، کلید پیش از مقدار ارزیابی میشود، همانطور که در PEP 572 پیشنهاد شده است.
6.2.9. عبارتهای تولیدگر¶
سینتکس عبارتهای تولیدگر <generator expressions> همانند درکهای فهرستی است، با این تفاوت که آنها به جای کروشه در پرانتز قرار میگیرند. برای مثال:
>>> iterator = (x ** 2 for x in range(10))
>>> iterator
<generator object <genexpr> at ...>
در رانتایم، یک عبارت تولیدگر به یک generator iterator ارزیابی میشود که همان مقادیرِ درک فهرستی متناظر را تولید میکند:
>>> list(iterator)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
بنابراین، مثال بالا تقریباً معادل تعریف و فراخوانی تابع تولیدگر زیر است:
def make_generator_of_squares(iterator):
for x in iterator:
yield x ** 2
make_generator_of_squares(iter(range(10)))
هنگامی که عبارت تولیدگر تنها آرگومان جایگاهی باشد و هیچ آرگومان کلیدواژهای وجود نداشته باشد، میتوان پرانتزهای دربرگیرنده را در فراخوانیها حذف کرد. برای جزئیات، بخش فراخوانیها را ببینید. برای مثال:
# The parentheses after `sum` are part of the call syntax:
>>> sum(x ** 2 for x in range(10))
285
# The generator needs its own parentheses if it's not the only argument:
>>> sum((x ** 2 for x in range(10)), start=1000)
1285
عبارت پیمایشپذیر در چپترین بند for بلافاصله ارزیابی میشود، بهطوری که خطایی که این عبارت پرتاب میکند، در نقطهای که عبارت تولیدگر تعریف میشود بروز میکند، نه در نقطهای که نخستین مقدار بازیابی میشود:
>>> (x ** 2 for x in nonexistent_iterable)
Traceback (most recent call last):
...
NameError: name 'nonexistent_iterable' is not defined
پس از ارزیابی عبارت، یک پیمایشگر از نتیجه ایجاد میشود، گویی که iter() بر روی آن فراخوانی شده است. هر خطایی که هنگام ایجاد پیمایشگر پرتاب شود نیز بلافاصله منتشر میشود:
>>> (x ** 2 for x in None)
Traceback (most recent call last):
...
TypeError: 'NoneType' object is not iterable
تمام عبارتهای دیگر بهصورت تنبل ارزیابی میشوند، به همان شیوهی تولیدگرهای معمولی (یعنی زمانی که از پیمایشگر خواسته شود مقداری را yield کند):
>>> iterator = (nonexistent_value for x in range(10))
>>> iterator
<generator object <genexpr> at ...>
>>> list(iterator)
Traceback (most recent call last):
...
NameError: name 'nonexistent_value' is not defined
>>> iterator = (x * y for x in range(10) for y in nonexistent_iterable)
>>> iterator
<generator object <genexpr> at ...>
>>> list(iterator)
Traceback (most recent call last):
...
NameError: name 'nonexistent_iterable' is not defined
برای جلوگیری از اخلال در عملکرد مورد انتظار خود عبارت تولیدگر، عبارتهای yield و yield from در محدوده تودرتوی ضمنی ممنوع هستند.
اگر یک عبارت تولیدگر شامل بندهای async for یا عبارات await باشد، به آن عبارت تولیدگر ناهمگام <asynchronous generator expression> گفته میشود. یک عبارت تولیدگر ناهمگام یک شیء تولیدگر ناهمگام جدید برمیگرداند که یک پیمایشگر ناهمگام است (به پیمایشگرهای ناهمگام مراجعه کنید).
دستور زبان صوری عبارتهای تولیدگر:
generator_expression: "("expressioncomp_for")"
اضافه شده در نسخهی 3.6: عبارات تولیدگر ناهمگام معرفی شدند.
تغییر یافته در نسخهی 3.7: پیش از پایتون 3.7، عبارات تولیدگر ناهمگام فقط میتوانستند در همروالهای async def ظاهر شوند. از 3.7 به بعد، هر تابعی میتواند از عبارات تولیدگر ناهمگام استفاده کند.
تغییر یافته در نسخهی 3.8: yield و yield from در محدودهی تودرتوی ضمنی ممنوع است.
6.2.10. عبارتهای yield¶
yield_atom: "("yield_expression")" yield_from: "yield" "from"expressionyield_expression: "yield"yield_list|yield_from
عبارت yield هنگام تعریف یک تابع تولیدگر یا یک تابع تولیدگر ناهمگام استفاده میشود و بنابراین فقط میتواند در بدنهی تعریف یک تابع استفاده شود. استفاده از عبارت yield در بدنهی یک تابع، آن تابع را به یک تابع تولیدگر تبدیل میکند، و استفاده از آن در بدنهی یک تابع async def، آن تابع همروال را به یک تابع تولیدگر ناهمگام تبدیل میکند. برای مثال:
def gen(): # defines a generator function
yield 123
async def agen(): # defines an asynchronous generator function
yield 123
به دلیل عوارض جانبی عبارات yield بر محدودهی دربرگیرنده، این عبارات مجاز نیستند بخشی از محدودههایی باشند که بهطور ضمنی برای پیادهسازی درکها و عبارات تولیدگر تعریف شدهاند.
تغییر یافته در نسخهی 3.8: عبارات yield در محدودههای تودرتوی ضمنی که برای پیادهسازی درکها و عبارات تولیدگر به کار میروند، ممنوع است.
توابع تولیدگر در ادامه توضیح داده شدهاند، در حالی که توابع تولیدگر ناهمگام بهطور جداگانه در بخش توابع تولیدگر ناهمگام توضیح داده شدهاند.
هنگامی که یک تابع تولیدگر فراخوانی میشود، یک پیمایشگر برمیگرداند که بهعنوان تولیدگر شناخته میشود. سپس آن تولیدگر اجرای تابع تولیدگر را کنترل میکند. اجرا زمانی آغاز میشود که یکی از متدهای تولیدگر فراخوانی شود. در آن هنگام، اجرا به نخستین عبارت yield میرسد، جایی که دوباره معلق میشود و مقدار yield_list را به فراخوانندهی تولیدگر برمیگرداند، یا اگر yield_list حذف شده باشد، None را برمیگرداند. منظور از معلق بودن این است که تمام وضعیت محلی حفظ میشود، از جمله انتسابهای کنونی متغیرهای محلی، اشارهگر دستور، پشتهی ارزیابی داخلی، و وضعیت هرگونه مدیریت استثنا. هنگامی که اجرا با فراخوانی یکی از متدهای تولیدگر از سر گرفته میشود، تابع میتواند دقیقاً بهگونهای پیش برود که گویی عبارت yield تنها یک فراخوانی خارجی دیگر باشد. مقدار عبارت yield پس از آنکه اجرا از سر گرفته شد، به متدی بستگی دارد که اجرا را از سر گرفته است. اگر از __next__() استفاده شود (معمولاً از طریق for یا تابع توکار next())، نتیجه None است. در غیر این صورت، اگر از send() استفاده شود، نتیجه مقداری خواهد بود که به آن متد ارسال شده است.
همهی این موارد باعث میشود توابع تولیدگر بسیار شبیه به همروالها باشند؛ آنها چندین بار yield میکنند، بیش از یک نقطهی ورود دارند و اجرای آنها میتواند معلق شود. تنها تفاوت این است که تابع تولیدگر نمیتواند کنترل کند که پس از yield، اجرا باید از کجا ادامه یابد؛ کنترل همیشه به فراخوانندهی تولیدگر منتقل میشود.
عبارتهای yield در هر جای یک ساختار try مجاز هستند. اگر تولیدگر پیش از نهایی شدن (با رسیدن تعداد ارجاعها به صفر یا زبالهروبی شدن) از سر گرفته نشود، متد close() پیمایشگر تولیدگر فراخوانی میشود تا امکان اجرای هر بند finally در انتظار فراهم شود.
هنگامی که از yield from <expr> استفاده میشود، عبارت ارائهشده باید پیمایشپذیر باشد. مقادیری که با پیمایش آن پیمایشپذیر تولید میشوند، مستقیماً به فراخوانندهی متدهای تولیدگر فعلی ارسال میشوند. هر مقداری که با send() ارسال شود و هر استثنایی که با throw() ارسال شود، در صورتی که پیمایشگر زیرین متدهای مناسب را داشته باشد، به آن ارسال میشود. در غیر این صورت، send() استثناهای AttributeError یا TypeError را پرتاب میکند، در حالی که throw() فقط استثنای ارسالشده را بلافاصله پرتاب میکند.
هنگامی که پیمایشگر زیربنایی به پایان میرسد، ویژگی value از نمونهی پرتابشدهی StopIteration به مقدار عبارت yield تبدیل میشود. این ویژگی میتواند یا هنگام پرتاب StopIteration بهصراحت تنظیم شود، یا وقتی زیرپیمایشگر یک تولیدگر باشد بهطور خودکار (با برگرداندن یک مقدار از زیرتولیدگر) تنظیم شود.
تغییر یافته در نسخهی 3.3: yield from <expr> افزوده شد تا جریان کنترل به یک زیرپیمایشگر (subiterator) واگذار شود.
هنگامی که عبارت yield تنها عبارت در سمت راست یک دستور انتساب باشد، میتوان پرانتزها را حذف کرد.
همچنین ملاحظه نمائید
- PEP 255 - تولیدگرهای ساده
پیشنهاد برای افزودن تولیدگرها و دستور
yieldبه پایتون.- PEP 342 - همروالها از طریق تولیدگرهای بهبودیافته
پیشنهادی برای بهبود API و سینتکس تولیدگرها، تا بتوان از آنها بهعنوان همروالهای ساده استفاده کرد.
- PEP 380 - سینتکس واگذاری به یک زیرتولیدگر
پیشنهاد برای معرفی سینتکس
yield_from، که واگذاری به زیرتولیدگرها را آسان میکند.- PEP 525 - تولیدگرهای ناهمگام
پیشنهادی که PEP 492 را با افزودن قابلیتهای تولیدگر به توابع همروال گسترش داد.
6.2.10.1. متدهای تولیدگر-پیمایشگر¶
این زیربخش متدهای یک پیمایشگر تولیدگر را شرح میدهد. میتوان از آنها برای کنترل اجرای یک تابع تولیدگر استفاده کرد.
توجه داشته باشید که فراخوانی هر یک از متدهای تولیدگر زیر، هنگامی که تولیدگر از قبل در حال اجرا است، باعث پرتاب یک استثنای ValueError میشود.
- generator.__next__()¶
اجرای یک تابع تولیدگر را آغاز میکند یا آن را از آخرین عبارت yield اجراشده از سر میگیرد. هنگامی که یک تابع تولیدگر با متد
__next__()از سر گرفته میشود، عبارت yield جاری همیشه بهNoneارزیابی میشود. سپس اجرا تا عبارت yield بعدی ادامه مییابد، جایی که تولیدگر دوباره معلق میشود، و مقدارyield_listبه فراخوانندهی__next__()بازگردانده میشود. اگر تولیدگر بدون اینکه مقدار دیگری yield کند خارج شود، استثنایStopIterationپرتاب میشود.این متد معمولاً بهصورت ضمنی فراخوانی میشود، مثلاً توسط یک حلقه
for، یا توسط تابع توکارnext().
- generator.send(value)¶
اجرا را از سر میگیرد و یک مقدار را به تابع تولیدگر «ارسال» میکند. آرگومان value به نتیجهی عبارت yield جاری تبدیل میشود. متد
send()مقدار بعدی تولیدشده توسط تولیدگر را برمیگرداند، یا اگر تولیدگر بدون تولید مقدار دیگری خارج شود،StopIterationرا پرتاب میکند. هنگامی کهsend()برای شروع تولیدگر فراخوانی میشود، باید باNoneبهعنوان آرگومان فراخوانی شود، زیرا هیچ عبارت yield وجود ندارد که بتواند مقدار را دریافت کند.
- generator.throw(value)¶
- generator.throw(type[, value[, traceback]])
استثنایی را در نقطهای که تولیدگر متوقف شده بود، پرتاب میکند و مقدار بعدیای را که تابع تولیدگر آن را تولید میکند، برمیگرداند. اگر تولیدگر بدون تولید مقدار دیگری خارج شود، استثنای
StopIterationپرتاب میشود. اگر تابع تولیدگر، استثنای ارسالشده را نگیرد یا استثنای متفاوتی پرتاب کند، آن استثنا به فراخواننده منتشر میشود.در استفاده معمول، این با یک نمونه استثنا فراخوانی میشود، مشابه روشی که از کلیدواژه
raiseاستفاده میشود.با این حال، برای سازگاری با نسخههای قدیمی، امضای دوم طبق قراردادی از نسخههای قدیمیتر پایتون پشتیبانی میشود. آرگومان type باید یک کلاس استثنا باشد و value باید یک نمونه استثنا باشد. اگر value ارائه نشود، سازندهی type برای ایجاد یک نمونه فراخوانی میشود. اگر traceback ارائه شود، روی استثنا تنظیم میشود؛ در غیر این صورت، ممکن است هر ویژگی
__traceback__موجود که در value ذخیرهشده باشد پاک شود.تغییر یافته در نسخهی 3.12: امضای دوم (type[, value[, traceback]]) منسوخ شده است و ممکن است در نسخهای آینده از پایتون حذف شود.
- generator.close()¶
استثنای
GeneratorExitرا در نقطهای که تابع تولیدگر در آن متوقف شده بود پرتاب میکند (معادل فراخوانیthrow(GeneratorExit)). این استثنا در عبارت yield که تولیدگر در آن متوقف شده بود پرتاب میشود. اگر تابع تولیدگر استثنا را بگیرد و مقداری را برگرداند، این مقدار ازclose()برگردانده میشود. اگر تابع تولیدگر از قبل بسته شده باشد، یاGeneratorExitرا پرتاب کند (با نگرفتن استثنا)،close()مقدارNoneرا برمیگرداند. اگر تولیدگر مقداری را yield کند، استثنایRuntimeErrorپرتاب میشود. اگر تولیدگر هر استثنای دیگری را پرتاب کند، آن استثنا به فراخواننده منتقل میشود. اگر تولیدگر از قبل به دلیل یک استثنا یا خروج عادی خارج شده باشد،close()مقدارNoneرا برمیگرداند و هیچ اثر دیگری ندارد.تغییر یافته در نسخهی 3.13: اگر یک تولیدگر هنگام بسته شدن مقداری برگرداند، آن مقدار توسط
close()برگردانده میشود.
6.2.10.2. مثالها¶
در اینجا یک مثال ساده آمده است که رفتار تولیدگرها و توابع تولیدگر را نشان میدهد:
>>> def echo(value=None):
... print("Execution starts when 'next()' is called for the first time.")
... try:
... while True:
... try:
... value = (yield value)
... except Exception as e:
... value = e
... finally:
... print("Don't forget to clean up when 'close()' is called.")
...
>>> generator = echo(1)
>>> print(next(generator))
Execution starts when 'next()' is called for the first time.
1
>>> print(next(generator))
None
>>> print(generator.send(2))
2
>>> generator.throw(TypeError, "spam")
TypeError('spam',)
>>> generator.close()
Don't forget to clean up when 'close()' is called.
برای مثالهایی که از yield from استفاده میکنند، به PEP 380: سینتکس واگذاری به زیرتولیدگر در «تازههای پایتون» مراجعه کنید.
6.2.10.3. توابع تولیدگر ناهمگام¶
وجود عبارت yield در تابع یا متدی که با async def تعریف شده است، آن تابع را بهعنوان یک تابع تولیدگر ناهمگام نیز تعریف میکند.
هنگامی که یک تابع تولیدگر ناهمگام فراخوانی میشود، یک پیمایشگر ناهمگام را بازمیگرداند که بهعنوان یک شیء تولیدگر ناهمگام شناخته میشود. سپس آن شیء اجرای تابع تولیدگر را کنترل میکند. یک شیء تولیدگر ناهمگام بهطور معمول در یک دستور async for در یک تابع همروال استفاده میشود، همانگونه که یک شیء تولیدگر در یک دستور for استفاده میشود.
فراخوانی یکی از متدهای تولیدگر ناهمگام یک شیء awaitable بازمیگرداند و اجرا هنگامی آغاز میشود که این شیء await شود. در آن هنگام، اجرا به نخستین عبارت yield میرسد، جایی که دوباره معلق میشود و مقدار yield_list را به همروال در انتظار بازمیگرداند. مانند یک تولیدگر، تعلیق به این معناست که تمام وضعیت محلی حفظ میشود، از جمله پیوندهای فعلی متغیرهای محلی، اشارهگر دستور، پشته ارزیابی داخلی و وضعیت هرگونه مدیریت استثنا. هنگامی که اجرا با await کردن شیء بعدی که توسط متدهای تولیدگر ناهمگام بازمیگردد، از سر گرفته شود، تابع میتواند دقیقاً همانطور پیش برود که گویی عبارت yield صرفاً یک فراخوانی خارجی دیگر باشد. مقدار عبارت yield پس از ازسرگیری، به متدی بستگی دارد که اجرا را از سر گرفته است. اگر از __anext__() استفاده شود، نتیجه None است. در غیر این صورت، اگر از asend() استفاده شود، نتیجه مقداری خواهد بود که به آن متد ارسال شده است.
اگر یک تولیدگر ناهمگام با break، لغو شدن وظیفه فراخوان، یا سایر استثناها پیش از موعد خارج شود، کد پاکسازی ناهمگام تولیدگر اجرا خواهد شد و ممکن است در زمینهای غیرمنتظره استثناهایی را پرتاب کند یا به متغیرهای زمینه دسترسی یابد—شاید پس از پایان عمر وظایفی که به آنها وابسته است، یا در جریان خاموش شدن حلقهی رویداد، هنگامی که قلاب زبالهروبی تولیدگر ناهمگام فراخوانی میشود. برای جلوگیری از این موضوع، فراخوان باید بهصراحت با فراخوانی متد aclose() تولیدگر ناهمگام را ببندد تا تولیدگر را نهاییسازی کند و در نهایت آن را از حلقهی رویداد جدا کند.
در یک تابع تولیدگر ناهمگام، عبارتهای yield در هر جایی از ساختار try مجاز هستند. با این حال، اگر یک تولیدگر ناهمگام پیش از نهایی شدن (با رسیدن شمار ارجاع به صفر یا با زبالهروبی شدن) از سر گرفته نشود، آنگاه یک عبارت yield درون ساختار try ممکن است منجر به اجرا نشدن بندهای finally در انتظار اجرا شود. در این حالت، بر عهده حلقه رویداد یا زمانبندِ در حال اجرای تولیدگر ناهمگام است که متد aclose() پیمایشگر تولیدگر ناهمگام را فراخوانی کند و شیء همروال حاصل را اجرا کند، تا بدین ترتیب امکان اجرای هر بند finally در انتظار اجرا فراهم شود.
برای رسیدگی به نهاییسازی هنگام پایان حلقه رویداد، یک حلقه رویداد باید یک تابع نهاییساز (finalizer) تعریف کند که یک پیمایشگرٔ تولیدگر ناهمگام را میگیرد و احتمالاً aclose() را فراخوانی میکند و همروال را اجرا مینماید. این نهاییساز را میتوان با فراخوانی sys.set_asyncgen_hooks() ثبت کرد. یک پیمایشگرٔ تولیدگر ناهمگام در نخستین پیمایش، نهاییساز ثبتشده را ذخیره میکند تا در زمان نهاییسازی فراخوانی شود. برای دیدن یک نمونهی مرجع از متد نهاییساز، پیادهسازی asyncio.Loop.shutdown_asyncgens در Lib/asyncio/base_events.py را ببینید.
عبارت yield from <expr> هنگام استفاده در یک تابع تولیدگر ناهمگام، خطای نحوی است.
6.2.10.4. متدهای تولیدگر-پیمایشگر ناهمگام¶
این زیربخش، متدهای پیمایشگر تولیدگر ناهمگام را شرح میدهد که برای کنترل اجرای تابع تولیدگر به کار میروند.
- async agen.__anext__()¶
یک awaitable برمیگرداند که هنگام اجرا، اجرای تولیدگر ناهمگام را آغاز میکند یا آن را در آخرین عبارت yield اجراشده از سر میگیرد. هنگامی که یک تابع تولیدگر ناهمگام با متد
__anext__()از سر گرفته شود، عبارت yield جاری همیشه در awaitable برگرداندهشده، بهNoneارزیابی میشود، که وقتی اجرا شود، به عبارت yield بعدی ادامه میدهد. مقدارyield_listعبارت yield، مقدار استثنایStopIterationاست که توسط همروال کاملشونده پرتاب میشود. اگر تولیدگر ناهمگام بدون اینکه مقدار دیگری را yield کند، خارج شود، awaitable در عوض یک استثناStopAsyncIterationپرتاب میکند، که نشان میدهد تکرار ناهمگام کامل شده است.این متد معمولاً بهصورت ضمنی توسط یک حلقهی
async forفراخوانی میشود.
- async agen.asend(value)¶
یک شیء انتظارپذیر (awaitable) بازمیگرداند که هنگام اجرا، اجرای تولیدگر ناهمگام را از سر میگیرد. همانند متد
send()برای یک تولیدگر، این متد یک مقدار را به تابع تولیدگر ناهمگام «ارسال» میکند و آرگومان value به نتیجهی عبارت yield جاری تبدیل میشود. شیء انتظارپذیر بازگرداندهشده توسط متدasend()، مقدار بعدی را که توسط تولیدگر yield شده است، بهعنوان مقدارStopIterationپرتابشده بازمیگرداند، یا اگر تولیدگر ناهمگام بدون yield کردن مقدار دیگری خارج شود،StopAsyncIterationرا پرتاب میکند. هنگامی کهasend()برای شروع تولیدگر ناهمگام فراخوانی میشود، باید باNoneبهعنوان آرگومان فراخوانی شود، زیرا هیچ عبارت yield وجود ندارد که بتواند مقدار را دریافت کند.
- async agen.athrow(value)¶
- async agen.athrow(type[, value[, traceback]])
یک شیء انتظارپذیر (awaitable) بازمیگرداند که در نقطهای که تولیدگر ناهمگام مکث کرده بود، استثنایی از نوع
typeپرتاب میکند و مقدار بعدی تولیدشده توسط تابع تولیدگر را بهعنوان مقدار استثنایStopIterationپرتابشده بازمیگرداند. اگر تولیدگر ناهمگام بدون تولید مقدار دیگری خارج شود، یک استثنایStopAsyncIterationتوسط awaitable پرتاب میشود. اگر تابع تولیدگر استثنای دادهشده را نگیرد یا استثنای دیگری پرتاب کند، آنگاه هنگامی که awaitable اجرا میشود، آن استثنا به فراخوانندهی awaitable منتشر میشود.تغییر یافته در نسخهی 3.12: امضای دوم (type[, value[, traceback]]) منسوخ شده است و ممکن است در نسخهای آینده از پایتون حذف شود.
- async agen.aclose()¶
یک شیء awaitable بازمیگرداند که هنگام اجرا، یک استثنای
GeneratorExitرا به درون تابع تولیدگر ناهمگام در نقطهای که متوقف شده بود پرتاب میکند. اگر تابع تولیدگر ناهمگام سپس بهصورت مناسب خارج شود، از قبل بسته شده باشد، یا استثنایGeneratorExitرا پرتاب کند (با نگرفتن استثنا)، آنگاه شیء awaitable بازگشتدادهشده یک استثنایStopIterationپرتاب خواهد کرد. هر شیء awaitable بعدی که توسط فراخوانیهای بعدی تولیدگر ناهمگام بازگشت داده شود، یک استثنایStopAsyncIterationپرتاب خواهد کرد. اگر تولیدگر ناهمگام مقداری را yield کند، شیء awaitable یک استثنایRuntimeErrorپرتاب میکند. اگر تولیدگر ناهمگام استثنای دیگری پرتاب کند، آن استثنا به فراخوانندهی شیء awaitable منتقل میشود. اگر تولیدگر ناهمگام از قبل به دلیل یک استثنا یا خروج عادی خارج شده باشد، آنگاه فراخوانیهای بعدیaclose()یک شیء awaitable بازمیگردانند که هیچ کاری انجام نمیدهد.
6.3. اولیهها¶
اولیهها نشاندهندهی محکمترین عملیات زبان هستند. سینتکس آنها به این صورت است:
primary:atom|attributeref|subscription|call
6.3.1. ارجاعهای ویژگی¶
ارجاع به ویژگی یک عبارت اصلی است که پس از آن یک نقطه و یک نام میآید:
attributeref:primary"."identifier
عبارت اصلی باید به شیئی از نوعی ارزیابی شود که از ارجاعهای ویژگی پشتیبانی میکند؛ بیشتر اشیاء نیز چنین هستند. سپس از این شیء خواسته میشود ویژگیای با نام آن شناسه تولید کند. نوع و مقدار تولیدشده توسط شیء تعیین میشود. ارزیابیهای متعدد یک ارجاع ویژگی یکسان ممکن است اشیاء متفاوتی تولید کنند.
این تولید را میتوان با بازنویسی متد __getattribute__() یا متد __getattr__() سفارشیسازی کرد. متد __getattribute__() ابتدا فراخوانی میشود و یا مقداری را برمیگرداند یا در صورت در دسترس نبودن ویژگی، AttributeError را پرتاب میکند.
اگر یک AttributeError پرتاب شود و شیء متد __getattr__() داشته باشد، آن متد بهعنوان جایگزین فراخوانی میشود.
6.3.2. زیرنویسیها و اسلایس کردنها¶
سینتکس زیرنویسی <subscription> معمولاً برای انتخاب یک عنصر از یک ظرف استفاده میشود -- برای مثال، برای دریافت یک مقدار از یک dict:
>>> digits_by_name = {'one': 1, 'two': 2}
>>> digits_by_name['two'] # Subscripting a dictionary using the key 'two'
2
در سینتکس زیرنویسی (subscription)، پس از شیء مورد زیرنویسی — یک اولیه — یک زیرنویس (subscript) <subscript> در کروشههای مربع قرار میگیرد. در سادهترین حالت، زیرنویس یک عبارت واحد است.
بسته به نوع شیءای که زیرنویس بر آن اعمال میشود، زیرنویس گاهی کلید (برای نگاشتها)، اندیس (برای دنبالهها)، یا آرگومان نوع (برای انواع عام) نامیده میشود. از نظر سینتکسی، همه اینها معادل هستند:
>>> colors = ['red', 'blue', 'green', 'black']
>>> colors[3] # Subscripting a list using the index 3
'black'
>>> list[str] # Parameterizing the list type using the type argument str
list[str]
در رانتایم، مفسر عبارت اصلی و زیرنویس را ارزیابی میکند و __getitem__() یا __class_getitem__() آن را که متد ویژه است، با زیرنویس بهعنوان آرگومان فراخوانی میکند. برای جزئیات بیشتر دربارهی اینکه کدامیک از این متدها فراخوانی میشود، __class_getitem__ در برابر __getitem__ را ببینید.
برای نشان دادن چگونگی کار زیرنویسی، میتوانیم یک شیء سفارشی تعریف کنیم که __getitem__() را پیادهسازی میکند و مقدار زیرنویس را چاپ میکند:
>>> class SubscriptionDemo:
... def __getitem__(self, key):
... print(f'subscripted with: {key!r}')
...
>>> demo = SubscriptionDemo()
>>> demo[1]
subscripted with: 1
>>> demo['a' * 3]
subscripted with: 'aaa'
برای جزئیات مربوط به نحوهی مدیریت زیرنویسی توسط انواع توکار، مستندات __getitem__() را ببینید.
از زیرنویسیها نیز میتوان بهعنوان هدف در دستورهای انتساب یا حذف استفاده کرد. در این موارد، مفسر بهترتیب بهجای __getitem__()، متد ویژه __setitem__() یا __delitem__() شیء مورد زیرنویسی را فراخوانی میکند.
>>> colors = ['red', 'blue', 'green', 'black']
>>> colors[3] = 'white' # Setting item at index
>>> colors
['red', 'blue', 'green', 'white']
>>> del colors[3] # Deleting item at index 3
>>> colors
['red', 'blue', 'green']
همهی شکلهای پیشرفتهی زیرنویس که در بخشهای بعدی مستند شدهاند، برای انتساب و حذف نیز قابل استفادهاند.
6.3.2.1. اسلایسها¶
شکل پیشرفتهتری از زیرنویسی، یعنی اسلایس کردن <slicing>، معمولاً برای استخراج بخشی از یک دنباله استفاده میشود. در این حالت، زیرنویس یک اسلایس است: حداکثر سه عبارت که با دونقطه از یکدیگر جدا شدهاند. هر یک از عبارتها ممکن است حذف شود، اما یک اسلایس باید دستکم شامل یک دونقطه باشد:
>>> number_names = ['zero', 'one', 'two', 'three', 'four', 'five']
>>> number_names[1:3]
['one', 'two']
>>> number_names[1:]
['one', 'two', 'three', 'four', 'five']
>>> number_names[:3]
['zero', 'one', 'two']
>>> number_names[:]
['zero', 'one', 'two', 'three', 'four', 'five']
>>> number_names[::2]
['zero', 'two', 'four']
>>> number_names[:-3]
['zero', 'one', 'two']
>>> del number_names[4:]
>>> number_names
['zero', 'one', 'two', 'three']
هنگامی که یک اسلایس ارزیابی میشود، مفسر یک شیء slice ایجاد میکند که ویژگیهای start، stop و step آن بهترتیب نتایج عبارتهای بین دونقطهها هستند. هر عبارت جاافتاده به None ارزیابی میشود. سپس این شیء slice به __getitem__() یا __class_getitem__() متد خاص، همانطور که در بالا ذکر شد، داده میشود.
# continuing with the SubscriptionDemo instance defined above:
>>> demo[2:3]
subscripted with: slice(2, 3, None)
>>> demo[::'spam']
subscripted with: slice(None, None, 'spam')
6.3.2.2. زیرنویسهای جداشده با ویرگول¶
همچنین میتوان زیرنویس را بهصورت دو یا چند عبارت یا اسلایس جداشده با کاما نیز مشخص کرد:
# continuing with the SubscriptionDemo instance defined above:
>>> demo[1, 2, 3]
subscripted with: (1, 2, 3)
>>> demo[1:2, 3]
subscripted with: (slice(1, 2, None), 3)
این شکل معمولاً با کتابخانههای عددی برای اسلایس دادههای چندبُعدی استفاده میشود. در این حالت، مفسر یک tuple از نتایج عبارتها یا اسلایسها میسازد و این tuple را به متد ویژه __getitem__() یا __class_getitem__()، همانطور که در بالا آمد، ارسال میکند.
همچنین میتوان زیرنویس را بهصورت یک عبارت یا اسلایس تنها بههمراه ویرگولی پس از آن، برای مشخص کردن یک تاپل تکعضوی به کار برد:
>>> demo['spam',]
subscripted with: ('spam',)
6.3.2.3. زیرنویسیهای «ستارهدار»¶
اضافه شده در نسخهی 3.11: عبارتهای درون tuple_slices میتوانند ستارهدار باشند. PEP 646 را ببینید.
عبارت زیرنویس میتواند شامل یک عبارت ستارهدار نیز باشد. در این حالت، مفسر نتیجه را در قالب یک تاپل واگشایی میکند و این تاپل را به __getitem__() یا __class_getitem__() منتقل میکند:
# continuing with the SubscriptionDemo instance defined above:
>>> demo[*range(10)]
subscripted with: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
میتوان عبارتهای ستارهدار را با عبارتهای جداشده با کاما و اسلایسها ترکیب کرد:
>>> demo['a', 'b', *range(3), 'c']
subscripted with: ('a', 'b', 0, 1, 2, 'c')
6.3.2.4. دستور زبان رسمی اشتراک¶
subscription:primary'['subscript']' subscript:single_subscript|tuple_subscriptsingle_subscript:proper_slice|assignment_expressionproper_slice: [expression] ":" [expression] [ ":" [expression] ] tuple_subscript: ','.(single_subscript|starred_expression)+ [',']
به یاد داشته باشید که عملگر | بیانگر انتخاب ترتیبی است. بهطور مشخص، در subscript، اگر هر دو جایگزین تطابق یابند، نخستین (single_subscript) اولویت دارد.
6.3.3. فراخوانیها¶
یک فراخوانی، یک شیء فراخوانیپذیر (برای مثال، یک تابع) را با دنبالهای از آرگومانها که ممکن است خالی باشد فراخوانی میکند:
call:primary"(" [argument_list[","] |comprehension] ")" argument_list:positional_arguments[","starred_and_keywords] [","keywords_arguments] |starred_and_keywords[","keywords_arguments] |keywords_argumentspositional_arguments:positional_item(","positional_item)* positional_item:assignment_expression| "*"expressionstarred_and_keywords: ("*"expression|keyword_item) ("," "*"expression| ","keyword_item)* keywords_arguments: (keyword_item| "**"expression) (","keyword_item| "," "**"expression)* keyword_item:identifier"="expression
ممکن است یک ویرگول پایانی اختیاری پس از آرگومانهای جایگاهی و کلیدواژهای وجود داشته باشد، اما بر معناشناسی تأثیری نمیگذارد.
عبارت اصلی باید به یک شیء فراخوانیپذیر ارزیابی شود (توابع تعریفشده توسط کاربر، توابع توکار، متدهای اشیاء توکار، اشیاء کلاس، متدهای نمونههای کلاس، و همه اشیایی که متد __call__() دارند، فراخوانیپذیر هستند). تمام عبارتهای آرگومان پیش از تلاش برای فراخوانی ارزیابی میشوند. برای سینتکس فهرستهای پارامتر صوری، به بخش تابع مراجعه کنید.
اگر آرگومانهای کلیدواژهای وجود داشته باشند، آنها ابتدا به آرگومانهای جایگاهی تبدیل میشوند، به شرح زیر. نخست، فهرستی از جایگاههای پر نشده برای پارامترهای صوری ایجاد میشود. اگر N آرگومان جایگاهی وجود داشته باشد، آنها در N جایگاه نخست قرار میگیرند. سپس، برای هر آرگومان کلیدواژهای، از شناسه برای تعیین جایگاه متناظر استفاده میشود (اگر شناسه با نام نخستین پارامتر صوری یکسان باشد، نخستین جایگاه استفاده میشود، و به همین ترتیب). اگر جایگاه از قبل پر شده باشد، استثنای TypeError پرتاب میشود. در غیر این صورت، آرگومان در جایگاه قرار میگیرد و آن را پر میکند (حتی اگر عبارت None باشد، جایگاه را پر میکند). هنگامی که همهی آرگومانها پردازش شدند، جایگاههایی که هنوز پر نشدهاند با مقدار پیشفرض متناظر از تعریف تابع پر میشوند. (مقادیر پیشفرض یک بار، هنگام تعریف تابع محاسبه میشوند؛ بنابراین، یک شیء تغییرپذیر مانند فهرست یا دیکشنری که بهعنوان مقدار پیشفرض استفاده شود، بین همهی فراخوانیهایی که برای جایگاه متناظر مقدار آرگومان مشخص نمیکنند، مشترک خواهد بود؛ معمولاً باید از این کار اجتناب شود.) اگر جایگاههای پر نشدهای وجود داشته باشند که هیچ مقدار پیشفرضی برای آنها مشخص نشده باشد، استثنای TypeError پرتاب میشود. در غیر این صورت، فهرست جایگاههای پر شده بهعنوان فهرست آرگومانها برای فراخوانی استفاده میشود.
یک پیادهسازی ممکن است توابع توکاری را ارائه دهد که پارامترهای جایگاهی آنها نام ندارند، حتی اگر برای اهداف مستندسازی «نامگذاریشده» باشند، و بنابراین نمیتوان آنها را با کلیدواژه ارسال کرد. در CPython، این حالت برای توابعی صدق میکند که در C پیادهسازی شدهاند و از PyArg_ParseTuple() برای تجزیه آرگومانهای خود استفاده میکنند.
اگر آرگومانهای جایگاهی بیشتری نسبت به جایگاههای پارامتر صوری وجود داشته باشد، استثنای TypeError پرتاب میشود، مگر اینکه یک پارامتر صوری با استفاده از سینتکس *identifier وجود داشته باشد؛ در این حالت، آن پارامتر صوری یک تاپل شامل آرگومانهای جایگاهی مازاد را دریافت میکند (یا یک تاپل خالی اگر هیچ آرگومان جایگاهی مازادی وجود نداشته باشد).
اگر آرگومان کلیدواژهای وجود داشته باشد که با نام یک پارامتر صوری مطابقت نداشته باشد، یک استثنای TypeError پرتاب میشود، مگر اینکه یک پارامتر صوری با استفاده از سینتکس **identifier وجود داشته باشد؛ در این حالت، آن پارامتر صوری یک دیکشنری حاوی آرگومانهای کلیدواژهای اضافی دریافت میکند (با استفاده از کلیدواژهها بهعنوان کلیدها و مقادیر آرگومانها بهعنوان مقادیر متناظر)، یا اگر آرگومان کلیدواژهای اضافی وجود نداشته باشد، یک دیکشنری خالی (جدید) دریافت میکند.
اگر سینتکس *expression در فراخوانی تابع آمده باشد، expression باید به یک پیمایشپذیر ارزیابی شود. با عناصر این پیمایشپذیرها چنان رفتار میشود که گویی آرگومانهای جایگاهی اضافی هستند. برای فراخوانی f(x1, x2, *y, x3, x4)، اگر y به یک دنباله y1، ...، yM ارزیابی شود، این معادل یک فراخوانی با M+۴ آرگومان جایگاهی x1، x2، y1، ...، yM، x3، x4 است.
پیامد این موضوع آن است که اگرچه سینتکس *expression ممکن است بعد از آرگومانهای کلیدواژهای صریح ظاهر شود، اما قبل از آرگومانهای کلیدواژهای (و هر آرگومان **expression — در زیر ببینید) پردازش میشود. بنابراین:
>>> def f(a, b):
... print(a, b)
...
>>> f(b=1, *(2,))
2 1
>>> f(a=1, *(2,))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() got multiple values for keyword argument 'a'
>>> f(1, *(2,))
1 2
استفاده همزمان از آرگومانهای کلیدواژهای و سینتکس *expression در یک فراخوانی غیرمعمول است، بنابراین در عمل این سردرگمی اغلب پیش نمیآید.
اگر سینتکس **expression در فراخوانی تابع وجود داشته باشد، expression باید به یک نگاشت ارزیابی شود؛ محتوای آن بهعنوان آرگومانهای کلیدواژهای اضافی در نظر گرفته میشود. اگر به پارامتری که با یک کلید مطابقت دارد، از قبل مقداری داده شده باشد (با یک آرگومان کلیدواژهای صریح، یا از واگشایی دیگری)، استثنای TypeError پرتاب میشود.
هنگامی که از **expression استفاده میشود، هر کلید در این نگاشت باید یک رشته باشد. هر مقدار از این نگاشت به اولین پارامتر رسمی واجد شرایط برای انتساب کلیدواژهای که نام آن برابر با کلید است، اختصاص مییابد. کلید لازم نیست یک شناسه پایتون باشد (برای مثال "max-temp °F" قابل قبول است، اگرچه با هیچ پارامتر رسمیای که بتوان آن را اعلان کرد مطابقت نخواهد داشت). اگر هیچ مطابقتی با یک پارامتر رسمی وجود نداشته باشد، جفت کلید-مقدار توسط پارامتر ** جمعآوری میشود، در صورتی که چنین پارامتری وجود داشته باشد، و در غیر این صورت، استثنای TypeError پرتاب میشود.
نمیتوان از پارامترهای صوری با سینتکس *identifier یا **identifier بهعنوان جایگاههای آرگومانهای جایگاهی یا نامهای آرگومانهای کلیدواژهای استفاده کرد.
تغییر یافته در نسخهی 3.5: فراخوانیهای تابع هر تعداد واگشایی * و ** را میپذیرند، آرگومانهای جایگاهی میتوانند پس از واگشاییهای پیمایشپذیر (*) بیایند، و آرگومانهای کلیدواژهای میتوانند پس از واگشاییهای دیکشنری (**) بیایند. در ابتدا توسط PEP 448 پیشنهاد شد.
یک فراخوانی همیشه مقداری را برمیگرداند، که ممکن است None باشد، مگر آنکه استثنایی را پرتاب کند. نحوه محاسبه این مقدار به نوع شیء فراخوانیپذیر بستگی دارد.
اگر اینطور باشد---
- یک تابع تعریفشده توسط کاربر:
بلوک کد مربوط به تابع اجرا میشود و فهرست آرگومانها به آن داده میشود. نخستین کاری که بلوک کد انجام میدهد، مقیدسازی پارامترهای صوری به آرگومانها است؛ این موضوع در بخش تابع توضیح داده شده است. هنگامی که بلوک کد یک دستور
returnرا اجرا میکند، مقدار بازگشتی فراخوانی تابع را مشخص میکند. اگر اجرا به انتهای بلوک کد برسد بدون آنکه دستورreturnاجرا شود، مقدار بازگشتیNoneاست.- یک تابع یا متد توکار:
نتیجه به مفسر بستگی دارد؛ برای توضیحات توابع و متدهای توکار به Built-in Functions مراجعه کنید.
- یک شیء کلاس:
یک نمونه جدید از آن کلاس بازگردانده میشود.
- یک متد نمونهی کلاس:
تابع تعریفشده توسط کاربر متناظر فراخوانی میشود، با فهرست آرگومانی که یک آیتم بیشتر از فهرست آرگومانهای فراخوانی دارد: نمونه اولین آرگومان میشود.
- یک نمونه از کلاس:
کلاس باید یک متد
__call__()تعریف کند؛ در این صورت اثر آن همانند حالتی است که گویی آن متد فراخوانیشده باشد.
6.4. عبارت await¶
اجرای همروال را بر روی یک شیء awaitable معلق میکند. فقط میتواند درون یک تابع همروال استفاده شود.
await_expr: "await" primary
اضافه شده در نسخهی 3.5.
6.5. عملگر توان¶
عملگر توان نسبت به عملگرهای یکعملوندی در سمت چپ خود، اولویت بیشتری دارد؛ این عملگر نسبت به عملگرهای یکعملوندی در سمت راست خود، اولویت کمتری دارد. سینتکس به این صورت است:
power: (await_expr|primary) ["**"u_expr]
بنابراین، در یک دنباله بدون پرانتز از عملگرهای توان و یکعملوندی، عملگرها از راست به چپ ارزیابی میشوند (این موضوع ترتیب ارزیابی عملوندها را محدود نمیکند): -1**2 برابر با -1 میشود.
عملگر توان همان معنایی را دارد که تابع توکار pow() هنگام فراخوانی با دو آرگومان دارد: این عملگر، آرگومان چپ خود را به توان آرگومان راست خود برمیگرداند. آرگومانهای عددی ابتدا به یک نوع مشترک تبدیل میشوند، و نتیجه از آن نوع است.
برای عملوندهای int، نتیجه همنوع با عملوندها است، مگر اینکه آرگومان دوم منفی باشد؛ در آن صورت، تمام آرگومانها به float تبدیل میشوند و نتیجهای از نوع float برگردانده میشود. برای مثال، 10**2 مقدار 100 را برمیگرداند، اما 10**-2 مقدار 0.01 را برمیگرداند.
رساندن 0.0 به توان منفی منجر به ZeroDivisionError میشود. رساندن یک عدد منفی به توان کسری منجر به یک عدد complex میشود. (در نسخههای پیشین، ValueError پرتاب میشد.)
این عملیات را میتوان با استفاده از متدهای ویژهی __pow__() و __rpow__() سفارشی کرد.
6.6. عملیات حسابی و بیتی یکعملوندی¶
تمام عملیات حسابی و بیتی یکعملوندی اولویت یکسانی دارند:
u_expr:power| "-"u_expr| "+"u_expr| "~"u_expr
عملگر یکعملوندی - (منفی)، منفیِ آرگومان عددی خود را برمیگرداند؛ این عملیات را میتوان با متد ویژه __neg__() بازنویسی کرد.
عملگر یکعملوندی + (مثبت) آرگومان عددی خود را بدون تغییر برمیگرداند؛ این عملیات را میتوان با متد ویژه __pos__() بازنویسی کرد.
عملگر یکعملوندی ~ (وارونسازی) وارونگی بیتی آرگومان عدد صحیح خود را حاصل میکند. وارونگی بیتی x به صورت -(x+1) تعریف شده است. این عملگر فقط بر اعداد صحیح یا اشیاء سفارشیای اعمال میشود که متد ویژه __invert__() را بازنویسی کردهاند.
در هر سه حالت، اگر آرگومان نوع مناسب نداشته باشد، استثنای TypeError پرتاب میشود.
6.7. عملیات حسابی دودویی¶
عملیات حسابی دودویی دارای سطوح اولویت مرسوم هستند. توجه داشته باشید که برخی از این عملیات بر برخی انواع غیرعددی نیز اعمال میشوند. به جز عملگر توان، تنها دو سطح وجود دارد، یکی برای عملگرهای ضربی و دیگری برای عملگرهای جمعی:
m_expr:u_expr|m_expr"*"u_expr|m_expr"@"m_expr|m_expr"//"u_expr|m_expr"/"u_expr|m_expr"%"u_expra_expr:m_expr|a_expr"+"m_expr|a_expr"-"m_expr
عملگر * (ضرب) حاصلضرب آرگومانهایش را به دست میدهد. آرگومانها باید یا هر دو عدد باشند، یا یکی از آرگومانها باید عدد صحیح و دیگری باید یک دنباله باشد. در حالت اول، اعداد به یک نوع حقیقی مشترک تبدیل میشوند و سپس در هم ضرب میشوند. در حالت دوم، تکرار دنباله انجام میشود؛ ضریب تکرار منفی، یک دنباله خالی به دست میدهد.
این عملیات را میتوان با استفاده از متدهای ویژهی __mul__() و __rmul__() سفارشیسازی کرد.
تغییر یافته در نسخهی 3.14: اگر تنها یکی از عملوندها یک عدد مختلط باشد، عملوند دیگر به یک عدد ممیز شناور تبدیل میشود.
عملگر @ (at) برای ضرب ماتریسی در نظر گرفته شده است. هیچیک از انواع توکار پایتون این عملگر را پیادهسازی نمیکنند.
این عملیات را میتوان با استفاده از متدهای ویژه __matmul__() و __rmatmul__() سفارشیسازی کرد.
اضافه شده در نسخهی 3.5.
عملگرهای / (تقسیم) و // (تقسیم کف) خارجقسمت آرگومانهای خود را برمیگردانند. آرگومانهای عددی ابتدا به یک نوع مشترک تبدیل میشوند. تقسیم اعداد صحیح یک مقدار شناور برمیگرداند، در حالی که تقسیم کفِ اعداد صحیح یک عدد صحیح نتیجه میدهد؛ نتیجه، حاصل تقسیم ریاضی است که تابع 'floor' بر آن اعمال شده است. تقسیم بر صفر استثنای ZeroDivisionError را پرتاب میکند.
عملیات تقسیم را میتوان با استفاده از متدهای ویژه __truediv__() و __rtruediv__() سفارشیسازی کرد. عملیات تقسیم کف را میتوان با استفاده از متدهای ویژه __floordiv__() و __rfloordiv__() سفارشیسازی کرد.
عملگر % (باقیمانده) باقیماندهی تقسیم آرگومان اول بر آرگومان دوم را برمیگرداند. آرگومانهای عددی ابتدا به یک نوع مشترک تبدیل میشوند. صفر بودن آرگومان سمت راست باعث پرتاب استثنای ZeroDivisionError میشود. آرگومانها ممکن است اعداد ممیز شناور باشند، برای مثال، 3.14%0.7 برابر 0.34 است (زیرا 3.14 برابر 4*0.7 + 0.34 است.) عملگر باقیمانده همیشه نتیجهای با همان علامت عملوند دوم خود (یا صفر) حاصل میکند؛ مقدار مطلق نتیجه اکیداً کوچکتر از مقدار مطلق عملوند دوم است [1].
عملگرهای تقسیم کف و باقیمانده با اتحاد زیر به یکدیگر مرتبط هستند: x == (x//y)*y + (x%y). تقسیم کف و باقیمانده همچنین با تابع توکار divmod() مرتبط هستند: divmod(x, y) == (x//y, x%y). [2].
علاوه بر انجام عملیات باقیمانده روی اعداد، اشیاء رشته نیز عملگر % را سربارگذاری کردهاند تا قالببندی رشته به سبک قدیمی (که به آن درونیابی (interpolation) نیز گفته میشود) انجام شود. سینتکس قالببندی رشته در مرجع کتابخانه پایتون، بخش printf-style String Formatting توضیح داده شده است.
عملیات باقیمانده را میتوان با استفاده از متدهای ویژه __mod__() و __rmod__() سفارشیسازی کرد.
عملگر تقسیم کف، عملگر باقیمانده (modulo)، و تابع divmod() برای اعداد مختلط تعریف نشدهاند. در عوض، در صورت مناسب بودن، با استفاده از تابع abs() آن را به یک عدد ممیز شناور تبدیل کنید.
عملگر + (جمع) حاصلجمع آرگومانهای خود را برمیگرداند. آرگومانها باید یا هر دو عدد یا هر دو دنبالههایی از یک نوع باشند. در حالت اول، اعداد به یک نوع حقیقی مشترک تبدیل میشوند و سپس با هم جمع میشوند. در حالت دوم، دنبالهها به یکدیگر الحاق میشوند.
این عملیات را میتوان با استفاده از متدهای ویژهی __add__() و __radd__() سفارشی کرد.
تغییر یافته در نسخهی 3.14: اگر تنها یکی از عملوندها یک عدد مختلط باشد، عملوند دیگر به یک عدد ممیز شناور تبدیل میشود.
عملگر - (تفریق)، تفاضل آرگومانهای خود را برمیگرداند. آرگومانهای عددی ابتدا به یک نوع حقیقی مشترک تبدیل میشوند.
این عملیات را میتوان با استفاده از متدهای ویژهی __sub__() و __rsub__() سفارشیسازی کرد.
تغییر یافته در نسخهی 3.14: اگر تنها یکی از عملوندها یک عدد مختلط باشد، عملوند دیگر به یک عدد ممیز شناور تبدیل میشود.
6.8. عملیات جابهجایی¶
عملیات جابهجایی اولویت پایینتری نسبت به عملیات حسابی دارند:
shift_expr:a_expr|shift_expr("<<" | ">>")a_expr
این عملگرها، اعداد صحیح را بهعنوان آرگومان میپذیرند. آنها آرگومان اول را به تعداد بیتهای تعیینشده توسط آرگومان دوم، به چپ یا راست شیفت میدهند.
عملیات شیفت چپ را میتوان با استفاده از متدهای ویژه __lshift__() و __rlshift__() سفارشیسازی کرد. عملیات شیفت راست را میتوان با استفاده از متدهای ویژه __rshift__() و __rrshift__() سفارشیسازی کرد.
شیفت راست به اندازهی n بیت بهصورت تقسیم کف بر pow(2,n) تعریف میشود. شیفت چپ به اندازهی n بیت بهصورت ضرب در pow(2,n) تعریف میشود.
6.9. عملیات بیتبهبیت دودویی¶
هر یک از سه عملیات بیتی، سطح اولویت متفاوتی دارد:
and_expr:shift_expr|and_expr"&"shift_exprxor_expr:and_expr|xor_expr"^"and_expror_expr:xor_expr|or_expr"|"xor_expr
عملگر & حاصل AND بیتبهبیت آرگومانهایش را برمیگرداند، که باید اعداد صحیح باشند یا یکی از آنها باید یک شیء سفارشی باشد که متدهای ویژه __and__() یا __rand__() را بازنویسی میکند.
عملگر ^ حاصل XOR بیتی (یا انحصاری) آرگومانهای خود را برمیگرداند؛ این آرگومانها باید عدد صحیح باشند یا یکی از آنها باید یک شیء سفارشی باشد که متدهای ویژهی __xor__() یا __rxor__() را بازنویسی کرده باشد.
عملگر | حاصل OR بیتی (شمولی) آرگومانهایش را برمیگرداند؛ آرگومانها باید عدد صحیح باشند یا یکی از آنها باید یک شیء سفارشی باشد که متدهای ویژهی __or__() یا __ror__() را بازنویسی میکند.
6.10. مقایسهها¶
برخلاف C، تمام عملیات مقایسهای در پایتون اولویت یکسانی دارند که از اولویت هر عملیات حسابی، جابهجایی یا عملیات بیتبهبیتی پایینتر است. همچنین برخلاف C، عبارتهایی مانند a < b < c تفسیری دارند که در ریاضیات مرسوم است:
comparison:or_expr(comp_operatoror_expr)* comp_operator: "<" | ">" | "==" | ">=" | "<=" | "!=" | "is" ["not"] | ["not"] "in"
مقایسهها مقادیر بولی را حاصل میکنند: True یا False. ممکن است متدهای مقایسه غنی <rich comparison methods> سفارشی، مقادیر غیربولی برگردانند. در این صورت، پایتون در زمینههای بولی، bool() را روی چنین مقداری فراخوانی میکند.
میتوان مقایسهها را بهصورت دلخواه زنجیرهای کرد، برای مثال x < y <= z معادل x < y and y <= z است، با این تفاوت که y تنها یک بار ارزیابی میشود (اما در هر دو حالت، وقتی x < y نادرست باشد، z اصلاً ارزیابی نمیشود).
بهطور رسمی، اگر a، b، c، ...، y، z عبارت باشند و op1، op2، ...، opN عملگرهای مقایسه باشند، آنگاه a op1 b op2 c ... y opN z معادل a op1 b and b op2 c and ... y opN z است، با این تفاوت که هر عبارت حداکثر یکبار ارزیابی میشود.
توجه داشته باشید که a op1 b op2 c به معنای هیچگونه مقایسهای بین a و c نیست، بنابراین، بهعنوان مثال، x < y > z کاملاً مجاز است (هرچند شاید زیبا نباشد).
6.10.1. مقایسههای مقدار¶
عملگرهای <، >، ==، >=، <= و != مقادیر دو شیء را مقایسه میکنند. لازم نیست این دو شیء نوع یکسانی داشته باشند.
فصل اشیاء، مقادیر و انواع بیان میکند که اشیاء دارای یک مقدار هستند (علاوه بر نوع و هویت). مقدار یک شیء در پایتون مفهومی نسبتاً انتزاعی است: برای مثال، هیچ روش دسترسی کانونیکالی برای مقدار یک شیء وجود ندارد. همچنین الزامی وجود ندارد که مقدار یک شیء به شکل خاصی ساخته شود، مثلاً از تمام ویژگیهای دادهای آن تشکیل شده باشد. عملگرهای مقایسهای مفهوم خاصی از اینکه مقدار یک شیء چیست را پیادهسازی میکنند. میتوان آنها را بهعنوان تعریفکنندهی مقدار یک شیء بهصورت غیرمستقیم، از طریق پیادهسازی مقایسهی خود در نظر گرفت.
از آنجا که همه انواع (مستقیم یا غیرمستقیم) زیرنوعهایی از object هستند، رفتار مقایسه پیشفرض را از object به ارث میبرند. انواع میتوانند رفتار مقایسه خود را با پیادهسازی متدهای مقایسه غنی <rich comparison methods> مانند __lt__() سفارشیسازی کنند، همانطور که در سفارشیسازی پایه توضیح داده شده است.
رفتار پیشفرض برای مقایسه برابری (== و !=) بر اساس هویت اشیء است. بنابراین، مقایسه برابری نمونههایی با هویت یکسان منجر به برابری میشود، و مقایسه برابری نمونههایی با هویتهای متفاوت منجر به نابرابری میشود. انگیزه این رفتار پیشفرض، این خواست است که همه اشیء باید بازتابی باشند (یعنی x is y دلالت بر x == y دارد).
مقایسه ترتیبی پیشفرض (<، >، <= و >=) ارائه نمیشود؛ تلاش برای آن باعث پرتاب TypeError میشود. انگیزهای برای این رفتار پیشفرض، نبود یک ناوردا مشابه با برابری است.
رفتار مقایسهی برابری پیشفرض، یعنی اینکه نمونههایی با هویتهای متفاوت همیشه نابرابر هستند، ممکن است با آنچه انواعی که تعریفی معقول از مقدار شیء و برابری مبتنی بر مقدار دارند به آن نیاز دارند، در تضاد باشد. چنین انواعی نیاز خواهند داشت که رفتار مقایسهی خود را سفارشیسازی کنند، و در واقع، تعدادی از انواع توکار این کار را انجام دادهاند.
فهرست زیر رفتار مقایسهای مهمترین انواع توکار را توضیح میدهد.
اعداد انواع عددی توکار (Numeric Types --- int, float, complex) و انواع کتابخانه استاندارد
fractions.Fractionوdecimal.Decimalرا میتوان در داخل یک نوع و بین انواع مختلف مقایسه کرد، با این محدودیت که اعداد مختلط از مقایسه ترتیبی پشتیبانی نمیکنند. در محدوده انواع درگیر، این اعداد از نظر ریاضی (الگوریتمی) بهدرستی و بدون از دست رفتن دقت مقایسه میشوند.مقادیر غیرعدد (not-a-number) یعنی
float('NaN')وdecimal.Decimal('NaN')خاص هستند. هر مقایسه ترتیبی یک عدد با یک مقدار غیرعدد، نادرست است. یک پیامد غیرشهودی این است که مقادیر غیرعدد با خودشان برابر نیستند. برای مثال، اگرx = float('NaN')باشد،3 < x،x < 3وx == xهمگی نادرست هستند، در حالی کهx != xدرست است. این رفتار با IEEE 754 سازگار است.NoneوNotImplementedتکنمونه هستند. PEP 8 توصیه میکند که مقایسه برای تکنمونهها باید همیشه باisیاis notانجام شود و هرگز از عملگرهای برابری استفاده نشود.دنبالههای دودویی (نمونههای
bytesیاbytearray) را میتوان درون نوعشان و بین انواعشان مقایسه کرد. این دنبالهها با استفاده از مقادیر عددی عناصرشان بهصورت واژهنامهای مقایسه میشوند.رشتهها (نمونههای
str) با استفاده از نقاط کد عددی یونیکدِ نویسههایشان (نتیجهی تابع توکارord()) بهصورت واژگانی مقایسه میشوند. [3]رشتهها و دنبالههای دودویی را نمیتوان بهصورت مستقیم مقایسه کرد.
دنبالهها (نمونههایی از
tuple،listیاrange) فقط میتوانند در محدوده هر یک از نوعهای خودشان مقایسه شوند، با این محدودیت که بازهها از مقایسه ترتیبی پشتیبانی نمیکنند. مقایسه برابری میان این نوعها منجر به نابرابری میشود و مقایسه ترتیبی میان این نوعهاTypeErrorرا پرتاب میکند.دنبالهها بهصورت لغتنامهای با مقایسهی عناصر متناظر مقایسه میشوند. ظروف توکار معمولاً فرض میکنند اشیاء یکسان با خودشان برابر هستند. این امر به آنها اجازه میدهد آزمونهای برابری برای اشیاء یکسان را دور بزنند تا کارایی بهبود یابد و ناورداهای داخلی خود را حفظ کنند.
مقایسه واژگانی بین مجموعههای توکار بهصورت زیر عمل میکند:
برای این که دو مجموعه برابر مقایسه شوند، باید از یک نوع باشند، طول یکسانی داشته باشند، و هر جفت از عناصر متناظر باید با هم برابر باشند (برای مثال،
[1,2] == (1,2)نادرست است زیرا نوع آنها یکسان نیست).مجموعههایی که از مقایسهی ترتیبی پشتیبانی میکنند، به همان ترتیب اولین عنصر نابرااسلایسان مرتب میشوند (برای مثال،
[1,2,x] <= [1,2,y]همان مقدارx <= yرا دارد). اگر عنصر متناظر وجود نداشته باشد، مجموعهی کوتاهتر در ترتیب مقدم است (برای مثال،[1,2] < [1,2,3]درست است).
نگاشتها (نمونههای
dict) اگر و فقط اگر جفتهای(key, value)برابر داشته باشند، برابر مقایسه میشوند. مقایسهی برابری کلیدها و مقدارها، بازتابیبودن را الزامی میکند.مقایسههای ترتیبی (
<،>،<=و>=) استثنایTypeErrorرا پرتاب میکنند.مجموعهها (نمونههایی از
setیاfrozenset) را میتوان در درون نوع خود و میان نوعهایشان مقایسه کرد.آنها عملگرهای مقایسهای ترتیبی را بهمعنای آزمونهای زیرمجموعه و ابرمجموعه تعریف میکنند. این روابط ترتیبهای کامل را تعریف نمیکنند (برای مثال، دو مجموعهی
{1,2}و{2,3}نه برابرند، نه زیرمجموعهی یکدیگرند و نه ابرمجموعهی یکدیگرند). بر همین اساس، مجموعهها آرگومانهای مناسبی برای توابعی که به ترتیب کامل وابستهاند نیستند (برای مثال،min()،max()وsorted()در صورت دریافت فهرستی از مجموعهها بهعنوان ورودی، نتایج تعریفنشده تولید میکنند).مقایسهی مجموعهها، خاصیت بازتابی عناصر آنها را اعمال میکند.
بیشتر انواع توکار دیگر متدهای مقایسهای پیادهسازیشده ندارند، بنابراین رفتار مقایسهای پیشفرض را به ارث میبرند.
کلاسهای تعریفشده توسط کاربر که رفتار مقایسهی خود را سفارشیسازی میکنند، باید در صورت امکان برخی قواعد سازگاری را رعایت کنند:
مقایسه برابری باید بازتابی باشد. به عبارت دیگر، اشیاء یکسان باید در مقایسه برابر باشند:
x is yدلالت برx == yداردمقایسه باید متقارن باشد. به عبارت دیگر، عبارتهای زیر باید نتیجهی یکسانی داشته باشند:
x == yوy == xx != yوy != xx < yوy > xx <= yوy >= xمقایسه باید ترایا باشد. مثالهای زیر (غیرجامع) این موضوع را نشان میدهند:
x > y and y > zدلالت برx > zداردx < y and y <= zدلالت برx < zداردمقایسه معکوس باید منجر به نقض بولی شود. به عبارت دیگر، عبارتهای زیر باید نتیجه یکسانی داشته باشند:
x == yوnot x != yx < yوnot x >= y(برای ترتیب کامل)x > yوnot x <= y(برای ترتیب کامل)دو عبارت آخر در مورد مجموعههای کاملاً مرتب صدق میکنند (برای مثال برای دنبالهها، اما نه برای مجموعهها یا نگاشتها). همچنین دکوراتور
@~functools.total_orderingرا ببینید.نتیجهی
hash()باید با برابری سازگار باشد. اشیایی که برابر هستند باید یا مقدار هش یکسانی داشته باشند، یا بهعنوان هشناپذیر (unhashable) علامتگذاری شوند.
پایتون این قوانین سازگاری را اعمال نمیکند. در واقع، مقدارهای غیرعدد (not-a-number) نمونهای از پیروی نکردن از این قوانین هستند.
6.10.2. عملیات آزمون عضویت¶
عملگرهای in و not in عضویت را آزمایش میکنند. x in s اگر x عضوی از s باشد بهصورت True ارزیابی میشود و در غیر این صورت بهصورت False ارزیابی میشود. x not in s نقیض x in s را برمیگرداند. همه دنبالههای توکار و انواع مجموعهای، و همچنین دیکشنری، از این پشتیبانی میکنند؛ برای دیکشنری، in آزمایش میکند که دیکشنری دارای کلید دادهشدهای است یا نه. برای انواع ظرف مانند فهرست، تاپل، مجموعه، frozenset، دیکشنری یا collections.deque، عبارت x in y معادل any(x is e or x == e for e in y) است.
برای انواع رشته و بایت، x in y اگر و فقط اگر x زیررشتهای از y باشد، True است. یک آزمون معادل y.find(x) != -1 است. رشتههای خالی همیشه زیررشتهای از هر رشته دیگری در نظر گرفته میشوند، بنابراین "" in "abc" مقدار True را برمیگرداند.
برای کلاسهای تعریفشده توسط کاربر که متد __contains__() را تعریف میکنند، اگر y.__contains__(x) یک مقدار درست برگرداند، x in y مقدار True را برمیگرداند و در غیر این صورت False را برمیگرداند.
برای کلاسهای تعریفشده توسط کاربر که __contains__() را تعریف نمیکنند اما __iter__() را تعریف میکنند، x in y برابر True است اگر در حین پیمایش روی y، مقداری z تولید شود که عبارت x is z or x == z برای آن درست باشد. اگر در حین پیمایش استثنایی پرتاب شود، گویی in آن استثنا را پرتاب کرده است.
در نهایت، پروتکل پیمایش بهسبک قدیمی آزموده میشود: اگر کلاسی __getitem__() را تعریف کند، x in y اگر و تنها در صورتی True است که یک اندیس عدد صحیح نامنفی i وجود داشته باشد، بهطوری که x is y[i] or x == y[i] برقرار باشد و هیچ اندیس عدد صحیح کوچکتری استثنا IndexError را پرتاب نکند. (اگر هر استثنا دیگری پرتاب شود، گویی in آن استثنا را پرتاب کرده است).
عملگر not in بهگونهای تعریف شده است که مقدار درستی معکوسِ in را داشته باشد.
6.10.3. مقایسههای هویت¶
عملگرهای is و is not هویت یک شیء را میسنجند: x is y اگر و تنها اگر x و y یک شیء یکسان باشند، درست است. هویت یک شیء با استفاده از تابع id() تعیین میشود. x is not y مقدار درستی معکوس را برمیگرداند. [4]
6.11. عملیات بولی¶
or_test:and_test|or_test"or"and_testand_test:not_test|and_test"and"not_testnot_test:comparison| "not"not_test
در عملیات بولی، و همچنین هنگامی که عبارات در دستورهای کنترل جریان به کار میروند، مقادیر زیر بهعنوان نادرست تفسیر میشوند: False، None، صفر عددی از تمام انواع، و رشتهها و ظروف خالی (شامل رشتهها، تاپلها، فهرستها، دیکشنریها، مجموعهها و frozensetها). تمام مقادیر دیگر بهعنوان درست تفسیر میشوند. اشیای تعریفشده توسط کاربر میتوانند مقدار درستی خود را با ارائهی متد __bool__() سفارشی کنند.
عملگر not اگر آرگومان آن نادرست باشد، True و در غیر این صورت False برمیگرداند.
عبارت x and y ابتدا x را ارزیابی میکند؛ اگر x نادرست باشد، مقدار آن برگردانده میشود؛ در غیر این صورت، y ارزیابی میشود و مقدار حاصل برگردانده میشود.
عبارت x or y ابتدا x را ارزیابی میکند؛ اگر x درست باشد، مقدار آن برگردانده میشود؛ در غیر این صورت، y ارزیابی میشود و مقدار حاصل برگردانده میشود.
توجه داشته باشید که نه and و نه or مقدار و نوعی را که برمیگردانند به False و True محدود نمیکنند، بلکه آخرین آرگومان ارزیابیشده را برمیگردانند. این موضوع گاهی مفید است؛ مثلاً اگر s رشتهای باشد که در صورت خالی بودن باید با یک مقدار پیشفرض جایگزین شود، عبارت s or 'foo' مقدار دلخواه را برمیگرداند. از آنجا که not باید مقدار جدیدی ایجاد کند، صرفنظر از نوع آرگومان خود یک مقدار بولی برمیگرداند (برای مثال، not 'foo' به جای '' مقدار False تولید میکند.)
6.12. عبارات انتساب¶
assignment_expression: [identifier":="]expression
یک عبارت انتساب (که گاهی به آن «عبارت نامدار» یا «والروس» نیز گفته میشود) یک expression را به یک identifier انتساب میدهد، و همزمان مقدار expression را نیز بازمیگرداند.
یکی از موارد استفادهی رایج، هنگام پردازش عبارات باقاعدهی تطبیقیافته است:
if matching := pattern.search(data):
do_something(matching)
یا، هنگام پردازش جریان پرونده بهصورت تکهای :
while chunk := file.read(9000):
process(chunk)
عبارات مقیدسازی باید هنگامی که بهعنوان دستورهای عبارتی استفاده میشوند و هنگامی که بهعنوان زیرعبارتهایی در عبارتهای اسلایس، شرطی، لامبدا، آرگومان کلیدواژهای و عبارتهای if در درک (comprehension-if) و در دستورهای assert، with و assignment به کار میروند، در پرانتز قرار گیرند. در هر جای دیگری که بتوان از آنها استفاده کرد، نیازی به پرانتز نیست، از جمله در دستورهای if و while.
اضافه شده در نسخهی 3.8: برای جزئیات بیشتر دربارهی عبارتهای انتساب، PEP 572 را ببینید.
6.13. عبارات شرطی¶
conditional_expression:or_test["if"or_test"else"expression] expression:conditional_expression|lambda_expr
یک عبارت شرطی (که گاهی به آن «عملگر سهتایی» گفته میشود) جایگزینی برای دستور if-else است. از آنجا که این یک عبارت است، مقداری برمیگرداند و میتواند بهعنوان یک زیرعبارت ظاهر شود.
عبارت x if C else y ابتدا شرط، یعنی C را ارزیابی میکند، نه x را. اگر C درست باشد، x ارزیابی میشود و مقدار آن بازگردانده میشود؛ در غیر این صورت، y ارزیابی میشود و مقدار آن بازگردانده میشود.
برای جزئیات بیشتر درباره عبارات شرطی، PEP 308 را ببینید.
6.14. لامبداها¶
lambda_expr: "lambda" [parameter_list] ":"expression
عبارات لامبدا (که گاهی فرمهای لامبدا نامیده میشوند) برای ایجاد توابع ناشناس استفاده میشوند. عبارت lambda parameters: expression یک شیء تابع حاصل میدهد. این شیء بینام مانند یک شیء تابعی رفتار میکند که به این صورت تعریف شده باشد:
def <lambda>(parameters):
return expression
برای سینتکس فهرستهای پارامتر، بخش تابع را ببینید. توجه داشته باشید که توابع ایجادشده با عبارتهای lambda نمیتوانند شامل دستور یا حاشیهنویسیها باشند.
6.15. فهرستهای عبارت¶
starred_expression: "*"or_expr|expressionflexible_expression:assignment_expression|starred_expressionflexible_expression_list:flexible_expression(","flexible_expression)* [","] starred_expression_list:starred_expression(","starred_expression)* [","] expression_list:expression(","expression)* [","] yield_list:expression_list|starred_expression"," [starred_expression_list]
مگر وقتی که بخشی از یک نمایش فهرست یا مجموعه باشد، یک فهرست عبارت شامل حداقل یک ویرگول، یک تاپل حاصل میدهد. طول تاپل برابر تعداد عبارتهای داخل فهرست است. عبارتها از چپ به راست ارزیابی میشوند.
ستاره * نشاندهندهی واگشایی پیمایشپذیر <iterable unpacking> است. عملوند آن باید یک پیمایشپذیر باشد. این پیمایشپذیر به دنبالهای از آیتمها بسط داده میشود که در محل واگشایی، در تاپل، فهرست یا مجموعهی جدید گنجانده میشوند.
اضافه شده در نسخهی 3.5: واگشایی پیمایشپذیرها در فهرستهای عبارت، که در ابتدا در PEP 448 پیشنهاد شد.
اضافه شده در نسخهی 3.11: هر آیتم در یک فهرست عبارت میتواند ستارهدار شود. PEP 646 را ببینید.
ویرگول پایانی فقط برای ایجاد یک تاپل تکآیتمی، مانند 1, لازم است؛ در تمام موارد دیگر اختیاری است. یک عبارت بدون ویرگول پایانی، تاپل ایجاد نمیکند، بلکه مقدار آن عبارت را برمیگرداند. (برای ایجاد یک تاپل خالی، از یک جفت پرانتز خالی استفاده کنید: ().)
6.16. ترتیب ارزیابی¶
پایتون عبارتها را از چپ به راست ارزیابی میکند. توجه داشته باشید که هنگام ارزیابی یک انتساب، سمت راست پیش از سمت چپ ارزیابی میشود.
در سطرهای زیر، عبارتها به ترتیب حسابی پسوندهایشان ارزیابی میشوند:
expr1, expr2, expr3, expr4
(expr1, expr2, expr3, expr4)
{expr1: expr2, expr3: expr4}
expr1 + expr2 * (expr3 - expr4)
expr1(expr2, expr3, *expr4, **expr5)
expr3, expr4 = expr1, expr2
6.17. اولویت عملگرها¶
جدول زیر اولویت عملگرها در پایتون را خلاصه میکند، از بالاترین اولویت (بیشترین اتصال) تا پایینترین اولویت (کمترین اتصال). عملگرهای موجود در یک جعبه، اولویت یکسانی دارند. مگر اینکه سینتکس بهصراحت ذکر شده باشد، عملگرها دودویی هستند. عملگرهای موجود در یک جعبه از چپ به راست گروهبندی میشوند (بهجز توانگیری و عبارتهای شرطی که از راست به چپ گروهبندی میشوند).
توجه داشته باشید که مقایسهها، آزمونهای عضویت و آزمونهای هویت، همگی اولویت یکسانی دارند و از ویژگی زنجیرهسازی چپبهراست برخوردارند، همانطور که در بخش مقایسهها توضیح داده شده است.
عملگر |
توضیح |
|---|---|
|
پیوند یا عبارت داخل پرانتز، نمایش فهرست، نمایش دیکشنری، نمایش مجموعه |
|
زیرنویسی (شامل اسلایس)، فراخوانی، ارجاع به ویژگی |
عبارت await |
|
|
توانرسانی [5] |
|
مثبت، منفی، نقیض بیتبهبیت |
|
ضرب، ضرب ماتریسی، تقسیم، تقسیم کف، باقیمانده [6] |
|
جمع و تفریق |
|
شیفتها |
|
و بیتبهبیت |
|
XOR بیتبهبیت |
|
یای بیتی (Bitwise OR) |
مقایسهها، از جمله آزمونهای عضویت و هویت |
|
نفی بولی |
|
و بولی |
|
یا بولی |
|
|
عبارت شرطی |
عبارت لامبدا |
|
|
عبارت انتساب |
پانویسها