diff --git a/source/changelog.rst b/source/changelog.rst
index de78d47..a70c07a 100644
--- a/source/changelog.rst
+++ b/source/changelog.rst
@@ -12,6 +12,18 @@
=============
+.. raw:: html
+
+ 00134 - یکشنبه ۳ اردیبهشت ۱۴۰۲
+
+* درس نهم ویرایش و بروزرسانی گردید.
+* شرح دستور ``match/case`` به درس نهم اضافه شد.
+* [`Issue #59 `__]
+
+
+
+----
+
.. raw:: html
00133 - شنبه ۲ اردیبهشت ۱۴۰۲
diff --git a/source/index.rst b/source/index.rst
index 064985a..7094e84 100644
--- a/source/index.rst
+++ b/source/index.rst
@@ -40,7 +40,7 @@
lessons/l07-string-and-bytes-in-python
lessons/l08-list-and-tuple-in-python
lessons/l08-set-and-dict-in-python
- lessons/l09
+ lessons/l09-control-flow-statements-in-python
lessons/l10
lessons/l11
lessons/l12
diff --git a/source/lessons/l09.rst b/source/lessons/l09-control-flow-statements-in-python.rst
similarity index 76%
rename from source/lessons/l09.rst
rename to source/lessons/l09-control-flow-statements-in-python.rst
index 4a95ae4..a2df69b 100644
--- a/source/lessons/l09.rst
+++ b/source/lessons/l09-control-flow-statements-in-python.rst
@@ -1,8 +1,11 @@
.. role:: emoji-size
.. meta::
- :description: کتاب آموزش زبان برنامه نویسی پایتون به فارسی، آموزش دستورهای کنترلی در پایتون، آموزش دستور انتخاب در پایتون، آموزش دستور تکرار در پایتون، if در پایتون، else در پایتون، حلقه در پایتون، for در پایتون
- :keywords: آموزش, آموزش پایتون, آموزش برنامه نویسی, پایتون, انواع شی, انواع داده, انواع شی در پایتون, انواع داده در پایتون, پایتون
+ :description: پایتون به پارسی - کتاب آنلاین و آزاد آموزش زبان برنامهنویسی پایتون - درس نهم: دستورهای کنترلی در پایتون
+ :keywords: آموزش, آموزش پایتون, آموزش برنامه نویسی, پایتون، حلقه تکرار در پایتون، for، while و match/case در پایتون، دستورهای انتخاب در پایتون، دستور if/elif/else در پایتون، شی iterator در پایتون
+
+
+.. _lesson-09:
درس ۰۹: دستورهای کنترلی در پایتون
@@ -10,7 +13,7 @@
.. figure:: /_static/pages/09-python-if-else-for-while.jpg
:align: center
- :alt: دستورهای کنترلی در پایتون
+ :alt: درس نهم: دستورهای کنترلی در پایتون
:class: page-image
Photo by `Lynda Sanchez `__
@@ -19,7 +22,7 @@
در حالت عادی جریان اجرای یک برنامه روند ثابتی دارد به این شکل که کدها سطر به سطر، از بالا به پایین خوانده و اجرا میشوند؛ دستورهای کنترلی امکانی برای کنترل یا تغییر این جریان ثابت است. با استفاده از این دستورها میتوان برای اجرای یک بلاک شرط تعیین کرد که اگر در زمان اجرا این شرط برقرار نباشد از اجرای بلاک صرف نظر خواهد شد یا میتوان شرایطی را به وجود آورد که اجرای یک بلاک را از میان چندین بلاک مشخص انتخاب گردد و همچنین میتوان اجرای یک بلاک را چندین بار تکرار کرد.
-این درس به بررسی دستورهای کنترلی پایتون در دو بخش «انتخاب» و «تکرار» اختصاص یافته است.
+این درس به بررسی دستورهای کنترلی پایتون در دو بخش «انتخاب» و «تکرار» اختصاص یافته است. در انتها نیز بنابر ضرورت به معرفی اشیای iterator در پایتون پرداخته شده است.
@@ -32,10 +35,16 @@
----
+
+.. _python-selection:
+
انتخاب
--------
-با استفاده از دستور انتخاب میتوان بر حسب شرایط برنامه در زمان اجرا تعیین کرد که آیا یک بلاک دستور اجرا شود یا خیر و همچنین از بین دو یا چند بلاک دستور کدام یک انتخاب و اجرا گردد. پایتون تنها یک ساختار انتخاب را ارایه میدهد که میتواند به سه شکل «تک انتخابی»، «دو انتخابی» و «چند انتخابی» پیادهسازی گردد؛ این ساختار به نام دستور ``if`` خوانده میشود و در ادامه بررسی خواهد شد.
+با استفاده از دستور انتخاب میتوان بر حسب شرایط برنامه در زمان اجرا تعیین کرد که آیا یک بلاک دستور اجرا شود یا خیر و همچنین از بین دو یا چند بلاک دستور کدام یک انتخاب و اجرا گردد. رایجترین دستور انتخاب در پایتون ``if`` است که میتواند به سه شکل «تک انتخابی»، «دو انتخابی» و «چند انتخابی» پیادهسازی گردد. این ساختار در ادامه بررسی خواهد شد.
+
+
+.. _python-if:
دستور if
~~~~~~~~~~
@@ -266,70 +275,121 @@
50-75 %
25-50 %
-.. rubric:: دستور switch/case
-در صورتی که سابقه برنامهنویسی با زبانهای دیگری همچون C و Java را داشته باشید حتما با دستور switch نیز آشنا هستید؛ **این دستور در زبان پایتون پیادهسازی نشده است**.
+.. _python-match-case:
-دستور switch مقداری را دریافت میکند و سپس آن را با مقدارهای هر case درون ساختار خود به ترتیب مقایسه میکند؛ در صورتی که این مقدار با یکی از case ها برابر باشد، دستورهای مرتبط با آن case را اجرا کرده و از بررسی دیگر case ها صرف نظر میکند. همچنین اگر مقدار دریافتی با هیچ یک از case ها مطابقت نداشته باشد دستورهای مربوط به بخش default (در صورت وجود) را اجرا میکند. در پایین نمونهایی از این دستور در زبان **Java** آورده شده است:
+دستور match/case
+~~~~~~~~~~~~~~~~~~~~
-.. code-block:: java
+در صورتی که سابقه برنامهنویسی با زبانهای دیگری همچون C و Java را داشته باشید حتما با دستور switch نیز آشنا هستید؛ تا پیش **از نسخه 3.10 پایتون** این دستور در زبان پایتون پیادهسازی نشده بود و تنها میتوانستیم از ساختار ``if/elif/else`` استفاده نماییم. ولی اکنون پایتون از ساختار مشابهی به نام ``match/case`` پشتیبانی میکند که ساختاری برابر زیر دارد (برای مطالعه بیشتر: [`PEP 634 `__] و [`PEP 635 `__] و [`PEP 636 `__])::
- int success;
- char grade = 'B';
-.. code-block:: java
+ match value:
+ case matching_rule_1: statement_1
+ case matching_rule_2: statement_2
+ case matching_rule_3: statement_3
+ .
+ .
+ .
- switch (grade) {
- case 'A':
- System.out.println("Excellent grade");
- success = 1;
- break;
- case 'B':
- System.out.println("Very good grade");
- success = 1;
- break;
- case 'C':
- System.out.println("Good grade");
- success = 1;
- break;
- case 'D':
- case 'E':
- case 'F':
- System.out.println("Low grade");
- success = 0;
- break;
- default:
- System.out.println("Invalid grade");
- success = -1;
- break;
- }
-
-برای پیادهسازی چنین ساختاری در پایتون میتوان از ``if/elif/else`` استفاده کرد:
-
-.. code-block:: python
-
- grade = 'B'
-
-.. code-block:: python
+این دستور یک مقدار را دریافت میکند و با الگوهای درج شده توسط ``case`` مطابقت میدهد (از بالا به پایین) و با نخستین عمل انطباق موفق، دستورهای مرتبط با آن را اجرا کرده و سپس پایان مییابد.
- if grade == 'A':
- print('Excellent grade')
- success = 1
- elif grade == 'B':
- print('Very good grade')
- success = 1
- elif grade in ('D', 'E', 'F'):
- print('Low grade')
- success = 0
- else:
- print('Invalid grade')
- success = -1
+خواهید دید که این دستور بسیار منعطف بوده و پیشرفتهتر از دستور ``switch`` سنتی است. با یک مثال ساده شروع میکنیم::
+
+ >>> list = [4, 5, 6, 0, 2, 1, 3]
+ >>>
+ >>> first_num = list[0]
+ >>>
+ >>> match first_num:
+ ... case 0: print('Zero')
+ ... case 1: print('One')
+ ... case 2: print('Two')
+ ... case 3: print('Three')
+ ... case 4: print('Four')
+ ... case 5: print('Five')
+ ... case 6: print('Six')
+ ...
+ Four
+ >>>
+
+در مثال بالا مقدار حروفی مربوط به عدد اندیس صفر از شی list چاپ خواهد شد.
+
+مثالی دیگر، تشخیص زوج بودن یک عدد::
+
+
+ >>> list = [4, 5, 6, 0, 2, 1, 3]
+ >>>
+ >>> first_num = list[0]
+ >>>
+ >>> match first_num % 2:
+ ... case 0:
+ ... print('The number is even')
+ ... case 1:
+ ... print('The number is odd')
+ ...
+ The number is even
+
+هدف اصلی از ایجاد دستور ``match/case`` در پایتون، سادهسازی و افزایش خوانایی کد در زمان استفاده از دستور ``if/elif/else`` است.
+
+
+هر بخش ``case`` میتواند بیش از یک انطباق را بررسی کند. برای این منظور میتوان از کاراکتر ``|`` برای جداسازی الگوها استفاده نمود::
+
+ >>> list = [4, 5, 6, 0, 2, 1, 3]
+ >>>
+ >>> first_num = list[0]
+ >>>
+ >>> match first_num:
+ ... case 0 | 2 | 4 | 6 | 8:
+ ... print('The number is even')
+ ... case 1 | 3 | 5 | 7 | 9:
+ ... print('The number is odd')
+ ...
+ The number is even
+
+همچنین میتوان یک ``case`` پیشفرض نیز برای این ساختار در نظر گرفت، برای پردازش مقدار در زمانی که با هیچ یک از الگوهای موجود تطابق پیدا نکرد. برای درج ``case`` پیشفرض از الگو ``_`` استفاده میگردد. این الگو در ساختار ``match/case`` با هر مقداری تظابق داده میشود و میبایست برای جلوگیری از خطاهای منطقی، حتما به عنوان آخرین ``case`` قرار داده شود::
+
+
+ >>> list = [1, 2, 3, 'A', 'A', 'AAA']
+ >>> first_num = list[-1]
+ >>> match first_num:
+ ... case 0 | 2 | 4 | 6 | 8:
+ ... print('The number is even')
+ ... case 1 | 3 | 5 | 7 | 9:
+ ... print('The number is odd')
+ ... case _:
+ ... print("The received value is not a number")
+ ...
+ The received value is not a number
+
+در بخش ``case`` حتی میتوان از دستور ``if`` نیز استفاده نمود::
+
+ >>> list = [4, -5, 6, 0, 2, -1, 3]
+ >>>
+ >>> num = list[0]
+ >>>
+ >>> match num:
+ ... case num if num < 0:
+ ... print('The number is negative')
+ ... case num if num == 0:
+ ... print('The number is zero')
+ ... case num if num > 0:
+ ... print('The number is positive')
+ ...
+ The number is positive
+
+به این نگارش یا سینتکس از دستور ``if`` در جامعه پایتون، تکنیک ``guard`` گفته میشود. در این ساختار متغیری که در پشت ``if`` قرار میگیرد، همان مقدار دریافتی است. این متغیر میتواند هر نامی داشته باشد ولی حتما میبایست با متغیر درون دستور ``if`` همنام باشد (در مثال بالا برای جلوگیری از ابهام، همنام با خود مقدار دریافتی در نظر گرفته شده است). در این شرایط چنانچه ارزیابی دستور ``if`` برابر مقدار ``True`` باشد، دستورهای ``case`` آن اجرا میگردد و در غیر اینصورت الگوی ``case`` بعدی مورد پردازش قرار خواهد گرفت.
+
+
+.. _python-repetition:
تکرار
-------
-گاهی نیاز پیدا میکنیم که بلاکی را چندین بار پشت سرهم اجرا نماییم. به ساختار تکرار «حلقه» (Loop) گفته میشود؛ در ادامه به بررسی ساختار دو حلقه ارایه شده در زبان پایتون خواهیم پرداخت.
+گاهی نیاز پیدا میکنیم که بلاکی را چندین بار پشت سرهم اجرا نماییم. به ساختار تکرار، «حلقه» (Loop) گفته میشود؛ در ادامه به بررسی ساختار دو حلقه ارایه شده در زبان پایتون خواهیم پرداخت.
+
+
+.. _python-while:
دستور while
~~~~~~~~~~~~~
@@ -447,6 +507,7 @@
>>>
+.. _python-for:
دستور for
~~~~~~~~~~
@@ -575,9 +636,9 @@
.. rubric:: تابع ``(range(stop``:
-این تابع [`اسناد پایتون 3x `__] یک شی از نوع ``range`` را برمیگرداند؛ این شی یک دنباله تغییر ناپذیر است که معمولا از آن برای پیمایش در حلقه ``for`` استفاده میشود. با تبدیل شی ``range`` به نوع لیست خواهیم دید که این شی یک دنباله مرتب از اعداد صفر تا آرگومان stop (و نه خود آن) است؛ آرگومان stop میبایست یک عدد صحیح مثبت باشد::
+این تابع [`اسناد پایتون `__] یک شی از نوع ``range`` را برمیگرداند؛ این شی یک دنباله تغییر ناپذیر است که معمولا از آن برای پیمایش در حلقه ``for`` استفاده میشود. با تبدیل شی ``range`` به نوع لیست خواهیم دید که این شی یک دنباله مرتب از اعداد صفر تا آرگومان stop (و نه خود آن) است؛ آرگومان stop میبایست یک عدد صحیح مثبت باشد::
- >>> r = range(10) # Python 3.x
+ >>> r = range(10)
>>> type(r)
@@ -636,45 +697,6 @@
>>> list(range(-2, -10, -2))
[-2, -4, -6, -8]
-در نسخههای 2x پایتون دو نسخه از این تابع وجود دارد: تابع ``range`` [`اسناد پایتون 2x `__] و تابع ``xrange`` [`اسناد پایتون 2x `__].
-
-خروجی تابع ``range`` یک شی از نوع لیست است::
-
- >>> r = range(10) # Python 2.x
-
- >>> type(r)
-
-
- >>> r
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
-
- >>> import sys
- >>> sys.getsizeof(r)
- 152
-
-
-
-ولی خروجی تابع ``xrange`` یک شی از نوع ``xrange`` میباشد::
-
- >>> r = xrange(10) # Python 2.x
-
- >>> type(r)
-
-
- >>> r
- xrange(10)
-
- >>> list(r)
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
-
- >>> import sys
- >>> sys.getsizeof(r)
- 40
-
-
-خروجی تابع ``xrange`` سادهتر و بهینه تر از خروجی تابع ``range`` است بنابراین معمولا پیشنهاد میشود که در حلقه ``for`` از تابع ``xrange`` استفاده شود؛ به همین دلیل میباشد که تابع ``range`` در نسخههای 3x پایتون حذف شده است و تنها تابع ``xrange`` باقیمانده که با نام و نوع ``range`` پیادهسازی شده است.
-
-* چگونگی استفاده و تعداد آرگومانهای هر دو تابع همانند نسخه 3x است که پیش از این بررسی شد.
.. rubric:: چند مثال ساده دیگر:
@@ -740,6 +762,8 @@
>>> [x ** 2 for x in range(5)]
[0, 1, 4, 9, 16]
+این عمل، List Comprehensions خوانده میشود که توسط درس سیزدهم شرح داده خواهد شد.
+
و به عنوان مثالهایی دیگر به نمونه کدهای پایین توجه نمایید::
>>> y = 7
@@ -784,9 +808,9 @@
4
>>>
-به نمونه کد بالا توجه نمایید؛ با هر بار تکرار حلقه یکم تمام دستورهای بدنه آن که شامل یک حلقه دیگر است اجرا میگردد. از متغیر ``i`` درون حلقه داخلی نیز استفاده شده است. در بار نخستِ اجرای حلقه بیرونی مقدار ``i`` برابر عدد ``1`` قرار داده میشود که در این صورت اجرای حلقه داخلی تنها یک بار تکرار میگردد (``1 == ((len(range(0, 1``) و یک مقدار ``1`` در خروجی نمایش داده میشود، بار دوم ``i`` برابر عدد ``2`` میشود و در نتیجه حلقه داخلی دو بار تکرار میگردد که بر اثر آن دو مقدار ``2`` در خروجی چاپ میگردد. این روند تا پایان تکرار حلقه بیرونی ادامه مییابد.
+به نمونه کد بالا توجه نمایید؛ با هر بار تکرار حلقه یکم تمام دستورهای بدنه آن که شامل یک حلقه دیگر است اجرا میگردد. از متغیر ``i`` درون حلقه داخلی نیز استفاده شده است. در بار نخستِ اجرای حلقه بیرونی مقدار ``i`` برابر عدد ``1`` قرار داده میشود که در این صورت اجرای حلقه داخلی تنها یک بار تکرار میگردد ``1 == ((len(range(0, 1`` و یک مقدار ``1`` در خروجی نمایش داده میشود، بار دوم ``i`` برابر عدد ``2`` میشود و در نتیجه حلقه داخلی دو بار تکرار میگردد که بر اثر آن دو مقدار ``2`` در خروجی چاپ میگردد. این روند تا پایان تکرار حلقه بیرونی ادامه مییابد.
-*تابع (یا دستور) print به صورت پیشفرض پس از اجرا و چاپ مقدار به سطر بعدی میرود. [در درس بعد چگونگی تغییر این رفتار بررسی خواهد شد]*
+*تابع print به صورت پیشفرض پس از اجرا و چاپ مقدار به سطر بعدی میرود. [در درس بعد چگونگی تغییر این رفتار بررسی خواهد شد]*
اگر از پیش با زبانهایی نظیر C یا Java آشنایی دارید؛ برای درک بهتر ساختار حلقه ``for`` پایتون نمونه کد پایین که به زبان Java است را در نظر بگیرید:
@@ -850,8 +874,8 @@
>>> s = 'python'
- >>> for i, v in enumerate(s):
- ... print('%s) %s' % (i, v * 7))
+ >>> for index, value in enumerate(s):
+ ... print('%s) %s' % (index, value * 7))
...
0) ppppppp
1) yyyyyyy
@@ -880,13 +904,19 @@
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
-.. rubric:: شی تکرارکننده
+.. _python-iterator:
+
+شی تکرارکننده (iterator)
+----------------------------------------------
در این بخش قصد داریم با مفهوم iterator (تکرارکننده) در پایتون آشنا شویم. برای این منظور بهتر است ابتدا مفهوم iterable (تکرارپذیر) را بدانیم.
-تمام انواع دنباله یک iterable هستند؛ در واقع به اشیایی با این قابلیت که بتوان در هر لحظه یک عضو درون آن را دستیابی نمود iterable گفته میشود. اکثر انواع آماده شی که در پایتون میشناسیم یک iterable است؛ انواع شی رشته، لیست، توپِل، دیکشنری، range ،zip (یا xrange) یا یک شی فایل (file) و هر شی از کلاسی که خودتان به همراه متدهای ویژه ``()__iter__`` یا ``()__getitem__`` تعریف نمایید یک iterable هستند.
+تمام انواع دنباله یک iterable هستند؛ در واقع به اشیایی با این قابلیت که بتوان در هر لحظه یک عضو درون آن را دستیابی نمود iterable گفته میشود. اکثر انواع آماده شی که در پایتون میشناسیم یک iterable است؛ انواع شی رشته، لیست، توپِل، دیکشنری، range ،zip یا یک شی فایل (file) و هر شی از کلاسی که خودتان به همراه متد ویژه ``()__iter__`` تعریف نمایید یک iterable هستند [`ویکیپایتون `__].
+
+در آینده پس از مطالعه دروس مربوط به شی گرایی (هفدهم تا بیست و دوم) قادر به ساخت کلاس و استفاده از متدهای ویژه در پایتون خواهید بود. در آن زمان می توانید خود با پیادهسازی متد ویژه ``()__next__`` یک شی iterator ایجاد نمایید. اما در این مرحله ما فرآیند ایجاد را با یک ماژول از کتابخانه استاندارد پایتون پیش خواهیم برد.
+
+میتوان یک شی iterator را تنها با استفاده از تابع آماده ``()iter`` [`اسناد پایتون `__] ایجاد کرد. این تابع یک شی iterable را به عنوان آرگومان دریافت میکند و یک شی iterator از آن بر میگرداند::
-شی iterator با استفاده از تابع آماده ``()iter`` [`اسناد پایتون `__] ایجاد میشود؛ این تابع یک شی iterable را به عنوان آرگومان دریافت میکند و آن را در قالب یک شی iterator بر میگرداند::
>>> L = [1, 2, 3, 4, 5]
>>> type(L)
@@ -930,15 +960,13 @@
>>> type(itr)
-یک شی iterator این قابلیت را دارد که میتوان عضوهای درون آن را یکی یکی با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) پیمایش کرد؛ این متد در بار نخستِ فراخوانی عضو یکم شی و در دفعات بعدی فراخوانی به ترتیب عضوهای بعدی را برمیگرداند::
+یک شی iterator این قابلیت را دارد که میتوان عضوهای درون آن را یکی یکی با استفاده از متد ``()__next__`` پیمایش کرد؛ این متد در بار نخستِ فراخوانی عضو یکم شی و در دفعات بعدی فراخوانی به ترتیب عضوهای بعدی را برمیگرداند::
>>> L = [1, 2, 3, 4, 5]
>>> itr = iter(L)
::
- >>> # Python 3.x
-
>>> itr.__next__()
1
>>> itr.__next__()
@@ -946,17 +974,6 @@
>>> itr.__next__()
3
-::
-
- >>> # Python 2.x
-
- >>> itr.next()
- 1
- >>> itr.next()
- 2
- >>> itr.next()
- 3
-
با فراخوانی پی در پی این متد و رسیدن به انتهای پیمایش؛ زمانی که دیگر عضوی برای برگرداندن وجود ندارد یک خطا - البته درست این است که بگوییم یک استثنا (Exception) - با نام ``StopIteration`` گزارش میگردد::
>>> itr.__next__()
@@ -970,8 +987,6 @@
این دقیقا همان کاری است که در دستور ``for`` به انجام میرسد. زمانی که از یک دنباله برای پیمایش در این دستور استفاده میکنید؛ ``for`` در پشت صحنه آن را به یک iterator تبدیل و سپس پیمایش یک به یک عضوها را آغاز میکند. در هر لحظه که ``StopIteration`` رخ دهد، متوجه پایان دنباله شده و تکرار حلقه را پایان میبخشد.
-در آینده توسط درس استثناها در پایتون خواهید دید که میتوان با ایجاد iterator و استفاده از دستور ``try/except`` [که در همان درس خواهید آموخت] یک حلقه ``while`` را به مانند حلقه ``for`` پیادهسازی کرد.
-
با استفاده از ماژول ``itertools`` میتوانید iterator های بینهایت (Infinite) یا بدون توقف ایجاد نمایید. برای نمونه تابع ``cycle`` درون این ماژول، شی iterator ای میسازد که در انتهای پیمایش متوقف نمیشود و از نو به ابتدای شی برگشته و عضو یکم را برمیگرداند::
@@ -1009,6 +1024,4 @@
:emoji-size:`😊` امیدوارم مفید بوده باشه
-`لطفا دیدگاه و سوالهای مرتبط با این درس خود را در کدرز مطرح نمایید. `_
-