From f5daa7285f13315350fb7d8181a7012304e36c9c Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Fri, 28 Jun 2019 19:14:02 +0430
Subject: [PATCH 001/294] create l13
---
index.rst | 1 +
lessons/l13.rst | 114 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 115 insertions(+)
create mode 100644 lessons/l13.rst
diff --git a/index.rst b/index.rst
index 696ada8..3a64957 100644
--- a/index.rst
+++ b/index.rst
@@ -27,6 +27,7 @@
lessons/l10
lessons/l11
lessons/l12
+ lessons/l13
log
donate
diff --git a/lessons/l13.rst b/lessons/l13.rst
new file mode 100644
index 0000000..43d06c5
--- /dev/null
+++ b/lessons/l13.rst
@@ -0,0 +1,114 @@
+.. role:: emoji-size
+
+.. meta::
+ :description: کتاب آنلاین و آزاد آموزش زبان برنامهنویسی پایتون به فارسی - درس سیزدهم تابع
+ :keywords: آموزش, آموزش پایتون, آموزش برنامه نویسی, پایتون, انواع شی, انواع داده, پایتون
+
+
+درس ۱۳: تابع - بخش دوم
+========================
+
+
+
+
+
+
+
+
+:emoji-size:`✔` سطح: متوسط
+
+----
+
+
+.. contents:: سرفصلها
+ :depth: 2
+
+----
+
+
+
+
+Decorator (تزئینگر)
+--------------------
+
+
+تزئینگرها یا همان **Decorator** ها توابعی هستند که به منظور پوشش (wrap) توابع یا کلاسهای دیگر پیادهسازی میشوند. Decoratorها در پایتون ابزار بسیار کاربردی و مفیدی هستند که به برنامهنویس این امکان را میدهند تا بدون تغییر در بدنه توابع و کلاسهای خود، رفتار و ویژگیهای آنها را گسترش دهد.
+
+برای پوشش یک تابع توسط Decorator از سینتکسی مشابه ``decorator_name@`` در بالای بخش سرآیند استفاده میشود:
+
+::
+
+ @decorator_name
+ def function_name():
+ print("Somthing!")
+
+
+ function_name()
+
+مفهومی که این سینتکس (``decorator_name`` + ``@``) در بالای بخش سرآیند یک تابع برای مفسر پایتون ایجاد میکند کاملا مشابه با سینتکس پایین است::
+
+ wrapper = decorator_name(function_name)
+ wrapper()
+
+هر چیزی در پایتون یک شی است حتی مفاهیم پیچیدهای به مانند تابع؛ از درس پیش نیز به خاطر داریم که تابع در پایتون یک موجودیت **”first-class“** است که یعنی میتوان تابع را مانند دیگر اشیا به صورت آرگومان به توابع دیگر ارسال نمود. نمونه کد بالا نیز نمایش ارسال یک تابع (``function_name``) به تابعی دیگر (``decorator_name``) است.
+
+
+به مثال پایین توجه نمایید:
+
+::
+
+ >>> def decorator_name(func):
+ ... def wrapper():
+ ... print("Something is happening before the function is called.")
+ ... func()
+ ... print("Something is happening after the function is called.")
+ ... return wrapper
+ ...
+ >>>
+ >>> @decorator_name
+ ... def function_name():
+ ... print("Somthing!")
+ ...
+ >>>
+ >>> function_name()
+ Something is happening before the function is called.
+ Somthing!
+ Something is happening after the function is called.
+ >>>
+
+نمونه کد بالا را میتوان با ساختار ساده زیر نیز در نظر گرفت:
+
+::
+
+ >>> def decorator_name(func):
+ ... def wrapper():
+ ... print("Something is happening before the function is called.")
+ ... func()
+ ... print("Something is happening after the function is called.")
+ ... return wrapper
+ ...
+ >>>
+ >>> def function_name():
+ ... print("Somthing!")
+ ...
+ >>>
+ >>> wrapper = decorator_name(function_name)
+ >>> wrapper()
+ Something is happening before the function is called.
+ Somthing!
+ Something is happening after the function is called.
+ >>>
+
+همانطور که با مقایسه دو نمونه کد بالا قابل مشاهده است، Decoratorها یک روپوش (wrapper) برای توابع و کلاسهای ما بوجود میآورند. در هنگام فراخوانی تابع ``function_name`` مفسر پایتون متوجه decorator آن شده است و به جای اجرا، یک نمونه شی از آن را به decorator مشخص شده (``decorator_name``) ارسال میکند و یک شی جدید که در اینجا با عنوان ``wrapper`` مشخص شده است را دریافت و اجرا میکند.
+
+
+
+
+|
+
+----
+
+:emoji-size:`😊` امیدوارم مفید بوده باشه
+
+
+
From 1cddb8d2031f9f64c1a35a67bb99c27603e7b689 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Sat, 29 Jun 2019 16:21:29 +0430
Subject: [PATCH 002/294] complete decorators and start generators
---
lessons/l13.rst | 180 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 176 insertions(+), 4 deletions(-)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index 43d06c5..004c0eb 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -28,11 +28,11 @@
-Decorator (تزئینگر)
---------------------
+Decorator
+----------
-تزئینگرها یا همان **Decorator** ها توابعی هستند که به منظور پوشش (wrap) توابع یا کلاسهای دیگر پیادهسازی میشوند. Decoratorها در پایتون ابزار بسیار کاربردی و مفیدی هستند که به برنامهنویس این امکان را میدهند تا بدون تغییر در بدنه توابع و کلاسهای خود، رفتار و ویژگیهای آنها را گسترش دهد.
+دکوراتور (تزئینگر) یا همان **Decorator** ها [`PEP 318 `__] به توابعی گفته میشود که به منظور پوشش (wrap) توابع یا کلاسهای دیگر پیادهسازی میشوند. Decoratorها در پایتون ابزار بسیار کاربردی و مفیدی هستند که به برنامهنویس این امکان را میدهند تا با کاهش حجم کدنویسی و بدون تغییر در بدنه توابع و کلاسهای خود، رفتار و ویژگیهای آنها را گسترش دهد. در این بخش تمرکز بر روی اعمال Decoratorها به توابع است و Decorator کلاس را در درس مربوط به کلاسها بررسی خواهیم کرد.
برای پوشش یک تابع توسط Decorator از سینتکسی مشابه ``decorator_name@`` در بالای بخش سرآیند استفاده میشود:
@@ -99,7 +99,179 @@ Decorator (تزئینگر)
Something is happening after the function is called.
>>>
-همانطور که با مقایسه دو نمونه کد بالا قابل مشاهده است، Decoratorها یک روپوش (wrapper) برای توابع و کلاسهای ما بوجود میآورند. در هنگام فراخوانی تابع ``function_name`` مفسر پایتون متوجه decorator آن شده است و به جای اجرا، یک نمونه شی از آن را به decorator مشخص شده (``decorator_name``) ارسال میکند و یک شی جدید که در اینجا با عنوان ``wrapper`` مشخص شده است را دریافت و اجرا میکند.
+همانطور که با مقایسه دو نمونه کد بالا قابل مشاهده است، Decoratorها یک روپوش (wrapper) برای توابع و کلاسهای ما بوجود میآورند. در هنگام فراخوانی تابع ``function_name`` مفسر پایتون متوجه decorator آن شده است و به جای اجرا، یک نمونه شی از آن را به decorator مشخص شده (``decorator_name``) ارسال میکند و یک شی جدید که در اینجا با تابع ``wrapper`` مشخص شده است را دریافت و اجرا میکند.
+
+در مورد توابع دارای پارامتر نیز باید توجه داشت که در هنگام فراخوانی تابع مورد نظر و ارسال آرگومان به تابع، مفسر پایتون این آرگومانها را به تابع ``wrapper`` از decorator ارسال میکند::
+
+ >>> def multiply_in_2(func):
+ ... def wrapper(*args):
+ ... return func(*args) * 2
+ ... return wrapper
+ ...
+ >>>
+ >>> @multiply_in_2
+ ... def sum_two_numbers(a, b):
+ ... return a + b
+ ...
+ >>>
+ >>> sum_two_numbers(2, 3)
+ 10
+
+::
+
+ >>> # normal
+ >>>
+ >>> def multiply_in_2(func):
+ ... def wrapper(*args):
+ ... return func(*args) * 2
+ ... return wrapper
+ ...
+ >>>
+ >>> def sum_two_numbers(a, b):
+ ... return a + b
+ ...
+ >>>
+ >>> wrapper = multiply_in_2(sum_two_numbers)
+ >>> wrapper(2, 3)
+ 10
+
+
+
+
+میتوان بیش از یک Decorator به کلاسها و توابع خود اعمال کرد که در این صورت ترتیب قرار گرفتن این Decoratorها برای مفسر پایتون دارای اهمیت است::
+
+ @decorator_3
+ @decorator_2
+ @decorator_1
+ def function_name():
+ print("Somthing!")
+
+
+ function_name()
+
+
+::
+
+ wrapper = decorator_3(decorator_2(decorator_1(function_name)))
+ wrapper()
+
+
+همچنین میتوان به Decoratorها آرگومان نیز ارسال کرد::
+
+ @decorator_name(params)
+ def function_name():
+ print("Somthing!")
+
+
+ function_name()
+
+در این حالت مفسر پایتون ابتدا آرگومان را به تابع Decorator ارسال میکند و سپس حاصل را با آرگومان ورودی تابع مورد نظر فراخوانی میکند::
+
+ temp_decorator = decorator_name(params)
+ wrapper = temp_decorator(function_name)
+ wrapper()
+
+به نمونه کد پایین توجه نمایید::
+
+ >>> def formatting(lowerscase=False):
+ ... def formatting_decorator(func):
+ ... def wrapper(text=''):
+ ... if lowerscase:
+ ... func(text.lower())
+ ... else:
+ ... func(text.upper())
+ ... return wrapper
+ ... return formatting_decorator
+ ...
+ >>>
+ >>> @formatting(lowerscase=True)
+ ... def chaap(message):
+ ... print(message)
+ ...
+ >>>
+ >>> chaap("I Love Python")
+ i love python
+ >>>
+
+
+Generator
+----------
+
+ژنراتور (مولد) یا همان **Generator** ها [`PEP 255 `__] به توابعی گفته میشود که به منظور ایجاد یک تابع با رفتاری مشابه اشیا ``iterator`` (تکرارکننده - درس نهم) پیادهسازی میشوند.
+
+بر خلاف شی لیست، عملکرد Generator به صورت **lazy** (کندرو) [`ویکیپدیا `__] میباشد و دادهها را یکجا ذخیره نمیکند بلکه آنها را تنها در همان زمانی که درخواست میشوند، **تولید** (Generate) میکند. بنابراین در هنگام برخورد با مجموعه دادههای بزرگ، Generatorها مدیریت حافظه کارآمدتری دارند.
+
+برای ایجاد یک تابع Generator تنها کافی است در یک تابع معمولی از دستور ``yield`` استفاده کنیم. اکنون مفسر پایتون در هنگام فراخوانی این تابع یک شی ``generator`` برمیگرداند که توانایی تولید یک **دنباله** (Sequence) از مقادیر (شی) برای استفاده در کاربردهای تکرارپذیر را دارد. به نمونه کد پایین توجه نمایید::
+
+
+ >>> def a_generator_function():
+ ... for i in range(3): # i: 0, 1, 2
+ ... yield i*i
+ ...
+ >>>
+ >>> my_generator = a_generator_function() # Create a generator
+ >>>
+ >>> type(my_generator)
+
+ >>>
+ >>> for i in my_generator:
+ ... print(i)
+ ...
+ 0
+ 1
+ 4
+ >>>
+
+دستور ``yield`` را میتوان همانند دستور ``return`` دانست با این تفاوت که پس از توقف اجرای تابع، وضعیت تابع را نیز حفظ میکند. به همین دلیل میتوان ادامه دنباله را از پی گرفت.
+
+
+::
+
+ >>> def a_generator_function():
+ ... for i in range(3):
+ ... yield i*i
+ ...
+ >>> my_generator = a_generator_function()
+ >>>
+ >>> my_generator.__next__() # Use my_generator.next() in Python 2.x
+ 0
+ >>> my_generator.__next__()
+ 1
+ >>> my_generator.__next__()
+ 4
+ >>> my_generator.__next__()
+ Traceback (most recent call last):
+ File "", line 1, in
+ StopIteration
+ >>>
+
+مقادیر دنباله مورد نظر خود را میتوانیم با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) درخواست نماییم. باید توجه داشت که پایان این دنباله توسط استثنا ``StopIteration`` گزارش میشود. در زمان استفاده از دستور ``for`` این استثنا کنترل شده و حلقه پایان میپذیرد.
+
+به یک نمونه کد دیگر نیز توجه نمایید::
+
+ >>> def countdown(n):
+ ... print("Counting down from %d" % n)
+ ... while n > 0:
+ ... yield n
+ ... n -= 1
+ ... return
+ ...
+ >>>
+ >>> countdown_generator = countdown(10)
+ >>>
+ >>> countdown_generator.__next__()
+ Counting down from 10
+ 10
+ >>> countdown_generator.__next__()
+ 9
+ >>> countdown_generator.__next__()
+ 8
+ >>> countdown_generator.__next__()
+ 7
+ >>>
+
+
+
From 28e8e13b5ea4f4c70ee0e66280ce39313070eab0 Mon Sep 17 00:00:00 2001
From: Saeid Darvishi
Date: Sun, 7 Jul 2019 00:11:31 +0430
Subject: [PATCH 003/294] work on yield - l13
---
lessons/l13.rst | 56 ++++++++++++++++++++++++++++++-------------------
1 file changed, 34 insertions(+), 22 deletions(-)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index 004c0eb..addd0ed 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -199,53 +199,65 @@ Generator
ژنراتور (مولد) یا همان **Generator** ها [`PEP 255 `__] به توابعی گفته میشود که به منظور ایجاد یک تابع با رفتاری مشابه اشیا ``iterator`` (تکرارکننده - درس نهم) پیادهسازی میشوند.
-بر خلاف شی لیست، عملکرد Generator به صورت **lazy** (کندرو) [`ویکیپدیا `__] میباشد و دادهها را یکجا ذخیره نمیکند بلکه آنها را تنها در همان زمانی که درخواست میشوند، **تولید** (Generate) میکند. بنابراین در هنگام برخورد با مجموعه دادههای بزرگ، Generatorها مدیریت حافظه کارآمدتری دارند.
+بر خلاف شی لیست، عملکرد Generator به صورت **lazy** (کندرو) [`ویکیپدیا `__] میباشد و دادهها را یکجا ذخیره نمیکند بلکه آنها را تنها در همان زمانی که درخواست میشوند، **تولید** (Generate) میکند. بنابراین در هنگام برخورد با مجموعه دادههای بزرگ، Generatorها مدیریت حافظه کارآمدتری دارند و همچینین ما مجبور نیستیم پیش از استفاده از یک دنباله منتظر بمانیم تا تمام مقادیر آن تولید شوند!.
-برای ایجاد یک تابع Generator تنها کافی است در یک تابع معمولی از دستور ``yield`` استفاده کنیم. اکنون مفسر پایتون در هنگام فراخوانی این تابع یک شی ``generator`` برمیگرداند که توانایی تولید یک **دنباله** (Sequence) از مقادیر (شی) برای استفاده در کاربردهای تکرارپذیر را دارد. به نمونه کد پایین توجه نمایید::
+برای ایجاد یک تابع Generator تنها کافی است در یک تابع معمولی از دستور ``yield`` استفاده کنیم.اکنون مفسر پایتون در هنگام فراخوانی این تابع یک شی ``generator`` برمیگرداند که توانایی تولید یک **دنباله** (Sequence) از مقادیر (شی) برای استفاده در کاربردهای تکرارپذیر را دارد.
+
+دستور ``yield`` روند اجرای برنامه را با حفظ وضعیت، متوقف میکند و میتوانیم با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) روند اجرای تابع را در دست بگیریم::
>>> def a_generator_function():
- ... for i in range(3): # i: 0, 1, 2
+ ... for i in range(3):
... yield i*i
...
- >>>
>>> my_generator = a_generator_function() # Create a generator
>>>
- >>> type(my_generator)
-
- >>>
- >>> for i in my_generator:
- ... print(i)
- ...
+ >>> my_generator.__next__() # Use my_generator.next() in Python 2.x
0
+ >>> my_generator.__next__()
1
+ >>> my_generator.__next__()
4
+ >>> my_generator.__next__()
+ Traceback (most recent call last):
+ File "", line 1, in
+ StopIteration
>>>
-دستور ``yield`` را میتوان همانند دستور ``return`` دانست با این تفاوت که پس از توقف اجرای تابع، وضعیت تابع را نیز حفظ میکند. به همین دلیل میتوان ادامه دنباله را از پی گرفت.
-::
+همانطور که در انتهای درس نهم (بخش «شی تکرارکننده») نیز اشاره شده بود، میتوانیم مقادیر دنباله مورد نظر خود را با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) درخواست نماییم. باید توجه داشت که پایان این دنباله توسط استثنا ``StopIteration`` گزارش میشود. در زمان استفاده از دستور ``for`` این استثنا کنترل شده و حلقه پایان میپذیرد. نمونه کد قبل را به صورت زیر بازنویسی میکنیم::
>>> def a_generator_function():
- ... for i in range(3):
+ ... for i in range(3): # i: 0, 1, 2
... yield i*i
...
- >>> my_generator = a_generator_function()
>>>
- >>> my_generator.__next__() # Use my_generator.next() in Python 2.x
+ >>> my_generator = a_generator_function() # Create a generator
+ >>>
+ >>> type(my_generator)
+
+ >>>
+ >>> for i in my_generator:
+ ... print(i)
+ ...
0
- >>> my_generator.__next__()
1
- >>> my_generator.__next__()
4
- >>> my_generator.__next__()
- Traceback (most recent call last):
- File "", line 1, in
- StopIteration
>>>
-مقادیر دنباله مورد نظر خود را میتوانیم با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) درخواست نماییم. باید توجه داشت که پایان این دنباله توسط استثنا ``StopIteration`` گزارش میشود. در زمان استفاده از دستور ``for`` این استثنا کنترل شده و حلقه پایان میپذیرد.
+
+**ویژگیهای تابع Generator**
+
+* تابع Generator یک تابع معمولی است که رفتاری مشابه با یک شی تکرارکننده (iterator) دارد.
+
+* تابع Generator شامل یک یا چند دستور ``yield`` میباشد.
+
+* در زمان فراخوانی تابع Generator، تابع اجرا نمیشود ولی در عوض یک شی از نوع ``generator`` برای آن تابع برگردانده میشود.
+
+* با استفاده از دستور ``yield`` میتوانیم در هر نقطهای از تابع Generator که بخواهیم توقف ایجاد کنیم - بدون از دست رفتن وضعیت فعلی تابع - و سپس با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) به ادامه روند اجرا برگردیم.
+
+
به یک نمونه کد دیگر نیز توجه نمایید::
From e9f3234e2e6f0b335eb15f51bdf82253f1fc1504 Mon Sep 17 00:00:00 2001
From: Saeid Darvishi
Date: Sun, 7 Jul 2019 00:12:39 +0430
Subject: [PATCH 004/294] add online python console
---
index.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/index.rst b/index.rst
index 3a64957..237656b 100644
--- a/index.rst
+++ b/index.rst
@@ -36,5 +36,9 @@
.. note::
کتاب در حال تکمیل است!.
+.. raw:: html
+
+
+
From f7fb87ea675430a1d2cd8d3ed697f127edc46db1 Mon Sep 17 00:00:00 2001
From: Saeid Darvishi
Date: Sun, 7 Jul 2019 00:16:48 +0430
Subject: [PATCH 005/294] change position of online python console
---
index.rst | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/index.rst b/index.rst
index 237656b..c62d637 100644
--- a/index.rst
+++ b/index.rst
@@ -33,12 +33,14 @@
|
-.. note::
- کتاب در حال تکمیل است!.
-
.. raw:: html
+|
+
+.. note::
+ کتاب در حال تکمیل است!.
+
From 8b61dd9d6f16fc02d8b085f22c099112d53f45a3 Mon Sep 17 00:00:00 2001
From: Saeid Darvishi
Date: Mon, 8 Jul 2019 00:20:01 +0430
Subject: [PATCH 006/294] complete generators - l13
---
lessons/l13.rst | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index addd0ed..ed5c76e 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -38,6 +38,10 @@ Decorator
::
+ def decorator_name(a_function):
+ pass
+
+
@decorator_name
def function_name():
print("Somthing!")
@@ -199,9 +203,9 @@ Generator
ژنراتور (مولد) یا همان **Generator** ها [`PEP 255 `__] به توابعی گفته میشود که به منظور ایجاد یک تابع با رفتاری مشابه اشیا ``iterator`` (تکرارکننده - درس نهم) پیادهسازی میشوند.
-بر خلاف شی لیست، عملکرد Generator به صورت **lazy** (کندرو) [`ویکیپدیا `__] میباشد و دادهها را یکجا ذخیره نمیکند بلکه آنها را تنها در همان زمانی که درخواست میشوند، **تولید** (Generate) میکند. بنابراین در هنگام برخورد با مجموعه دادههای بزرگ، Generatorها مدیریت حافظه کارآمدتری دارند و همچینین ما مجبور نیستیم پیش از استفاده از یک دنباله منتظر بمانیم تا تمام مقادیر آن تولید شوند!.
+بر خلاف شیای به مانند لیست، عملکرد Generator به صورت **lazy** (کندرو) [`ویکیپدیا `__] میباشد و دادهها را یکجا ذخیره نمیکند بلکه آنها را تنها در همان زمانی که درخواست میشوند، **تولید** (Generate) میکند. بنابراین در هنگام برخورد با مجموعه دادههای بزرگ، Generatorها مدیریت حافظه کارآمدتری دارند و همچنین ما مجبور نیستیم پیش از استفاده از یک دنباله منتظر بمانیم تا تمام مقادیر آن تولید شوند!.
-برای ایجاد یک تابع Generator تنها کافی است در یک تابع معمولی از دستور ``yield`` استفاده کنیم.اکنون مفسر پایتون در هنگام فراخوانی این تابع یک شی ``generator`` برمیگرداند که توانایی تولید یک **دنباله** (Sequence) از مقادیر (شی) برای استفاده در کاربردهای تکرارپذیر را دارد.
+برای ایجاد یک تابع Generator تنها کافی است در یک تابع معمولی از دستور ``yield`` استفاده کنیم. اکنون مفسر پایتون در هنگام فراخوانی این تابع یک شی ``generator`` برمیگرداند که توانایی تولید یک **دنباله** (Sequence) از مقادیر (شی) برای استفاده در کاربردهای تکرارپذیر را دارد.
دستور ``yield`` روند اجرای برنامه را با حفظ وضعیت، متوقف میکند و میتوانیم با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) روند اجرای تابع را در دست بگیریم::
@@ -209,6 +213,7 @@ Generator
>>> def a_generator_function():
... for i in range(3):
... yield i*i
+ ... return
...
>>> my_generator = a_generator_function() # Create a generator
>>>
@@ -231,6 +236,7 @@ Generator
>>> def a_generator_function():
... for i in range(3): # i: 0, 1, 2
... yield i*i
+ ... return
...
>>>
>>> my_generator = a_generator_function() # Create a generator
@@ -247,7 +253,9 @@ Generator
>>>
-**ویژگیهای تابع Generator**
+ویژگیهای تابع Generator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
* تابع Generator یک تابع معمولی است که رفتاری مشابه با یک شی تکرارکننده (iterator) دارد.
@@ -257,6 +265,14 @@ Generator
* با استفاده از دستور ``yield`` میتوانیم در هر نقطهای از تابع Generator که بخواهیم توقف ایجاد کنیم - بدون از دست رفتن وضعیت فعلی تابع - و سپس با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) به ادامه روند اجرا برگردیم.
+* با نخستین فراخوانی متد ``()__next__`` تابع اجرا میشود، تا زمانی که به یک دستور ``yield`` برسد. در این زمان دستور ``yield`` یک نتیجه تولید میکند و اجرای تابع متوقف میشود. با فراخوانی مجدد متد ``()__next__`` اجرای تابع از ادامه دستور ``yield`` سر گرفته میشود.
+
+* معمولا نیازی به استفاده مستقیم از متد ``()__next__`` نمیشود و توابع Generator از طریق دستورهایی به مانند ``for`` یا توابعی به مانند ``()sum`` و... که توانایی دریافت یک **دنباله** (Sequence) را دارند، مورد استفاده قرار میگیرند.
+
+* در پایان تولید توابع Generator یک استثنا ``StopIteration`` در نقطه توقف خود گزارش میدهند که میبایست درون برنامه کنترل شود.
+
+* فراموش نکنیم که استفاده از دستور ``return`` در هر کجا از بدنه تابع باعث پایان یافتن اجرای تابع در آن نقطه میشود و توابع Generator نیز از این امر مسثنا نیستند .
+
به یک نمونه کد دیگر نیز توجه نمایید::
@@ -283,6 +299,8 @@ Generator
>>>
+در ادامه Yield و Coroutines
+------------------------------------
From 18d02b7e1f6576e475e6e73e0b72650319a18a4c Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Mon, 7 Oct 2019 00:09:30 +0330
Subject: [PATCH 007/294] work on l13
---
lessons/l13.rst | 51 +++++++++++++++++++++++++++++--------------------
1 file changed, 30 insertions(+), 21 deletions(-)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index ed5c76e..d0f2533 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -201,17 +201,19 @@ Decorator
Generator
----------
-ژنراتور (مولد) یا همان **Generator** ها [`PEP 255 `__] به توابعی گفته میشود که به منظور ایجاد یک تابع با رفتاری مشابه اشیا ``iterator`` (تکرارکننده - درس نهم) پیادهسازی میشوند.
+ژنراتور (مولد) یا همان **Generator** ها [`PEP 255 `__] به توابعی گفته میشوند که به منظور ایجاد یک تابع با رفتاری مشابه اشیا ``iterator`` (تکرارکننده - درس نهم) پیادهسازی میگردند.
-بر خلاف شیای به مانند لیست، عملکرد Generator به صورت **lazy** (کندرو) [`ویکیپدیا `__] میباشد و دادهها را یکجا ذخیره نمیکند بلکه آنها را تنها در همان زمانی که درخواست میشوند، **تولید** (Generate) میکند. بنابراین در هنگام برخورد با مجموعه دادههای بزرگ، Generatorها مدیریت حافظه کارآمدتری دارند و همچنین ما مجبور نیستیم پیش از استفاده از یک دنباله منتظر بمانیم تا تمام مقادیر آن تولید شوند!.
+هنگام فراخوانی یک تابع معمولی، بدنه تابع اجرا میشود تا به یک دستور ``return`` برسد و خاتمه یابد ولی با فراخوانی یک تابع Generator، بدنه تابع اجرا نمیشود بلکه یک شی ``generator`` برگردانده خواهد شد که میتوان با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) آن، مقادیر مورد انتظار خود را یکی پس از دیگری درخواست داد.
-برای ایجاد یک تابع Generator تنها کافی است در یک تابع معمولی از دستور ``yield`` استفاده کنیم. اکنون مفسر پایتون در هنگام فراخوانی این تابع یک شی ``generator`` برمیگرداند که توانایی تولید یک **دنباله** (Sequence) از مقادیر (شی) برای استفاده در کاربردهای تکرارپذیر را دارد.
+عملکرد Generator به صورت **lazy** (کندرو) [`ویکیپدیا `__] میباشد و دادهها را یکجا ذخیره نمیکند بلکه آنها را تنها در همان زمانی که درخواست میشوند، **تولید** (Generate) میکند. بنابراین در هنگام برخورد با مجموعه دادههای بزرگ، Generatorها مدیریت حافظه کارآمدتری دارند و همچنین ما مجبور نیستیم پیش از استفاده از یک دنباله منتظر بمانیم تا تمام مقادیر آن تولید شوند!.
-دستور ``yield`` روند اجرای برنامه را با حفظ وضعیت، متوقف میکند و میتوانیم با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) روند اجرای تابع را در دست بگیریم::
+برای ایجاد یک تابع Generator تنها کافی است در یک تابع معمولی از یک یا چند دستور ``yield`` استفاده کنیم. اکنون مفسر پایتون در هنگام فراخوانی چنین تابعی یک شی ``generator`` برمیگرداند که توانایی تولید یک **دنباله** (Sequence) از مقادیر (یا شی) برای استفاده در کاربردهای تکرارپذیر را دارد.
+
+سینتکس دستور ``yield`` شبیه دستور ``return`` است ولی با کاربردی متفاوت. این دستور در هر نقطهای از بدنه تابع که باشد، اجرای برنامه را در آن نقطه متوقف میکند و ما میتوانیم با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) مقدار **yield (حاصل) شده** را دریافت نماییم::
>>> def a_generator_function():
- ... for i in range(3):
+ ... for i in range(3): # i: 0, 1, 2
... yield i*i
... return
...
@@ -229,9 +231,7 @@ Generator
StopIteration
>>>
-
-
-همانطور که در انتهای درس نهم (بخش «شی تکرارکننده») نیز اشاره شده بود، میتوانیم مقادیر دنباله مورد نظر خود را با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) درخواست نماییم. باید توجه داشت که پایان این دنباله توسط استثنا ``StopIteration`` گزارش میشود. در زمان استفاده از دستور ``for`` این استثنا کنترل شده و حلقه پایان میپذیرد. نمونه کد قبل را به صورت زیر بازنویسی میکنیم::
+باید توجه داشت که پایان فرآیند تولید تابع Generator توسط استثنا ``StopIteration`` گزارش میشود. البته در زمان استفاده از دستورهایی به مانند ``for`` این استثنا کنترل شده و حلقه پایان میپذیرد. نمونه کد قبل را به صورت زیر بازنویسی میکنیم::
>>> def a_generator_function():
... for i in range(3): # i: 0, 1, 2
@@ -239,12 +239,7 @@ Generator
... return
...
>>>
- >>> my_generator = a_generator_function() # Create a generator
- >>>
- >>> type(my_generator)
-
- >>>
- >>> for i in my_generator:
+ >>> for i in a_generator_function():
... print(i)
...
0
@@ -252,26 +247,38 @@ Generator
4
>>>
+به منظور درک بهتر عملکرد تابع Generator، تصور کنید از شما خواسته شده است که یک تابع شخصی مشابه با تابع ``()range`` پایتون پیادهسازی نمایید. راهکار شما چه خواهد بود؟ ایجاد یک شیای مانند لیست (list) یا تاپل خالی و پر کردن آن با استفاده از یک حلقه؟! این راهکار شاید برای ایجاد بازههای کوچک پاسخگو باشد ولی برای ایجاد یک بازه صد میلیونی آیا حافظه و زمان کافی در اختیار دارید؟. این مسئله را با استفاده از تابع Generator به سادگی و درستی حل خواهیم کرد::
+
+ >>> def my_range(stop):
+ ... number = 0
+ ... while number < stop:
+ ... yield number
+ ... number = number + 1
+ ... return
+ ...
+ >>>
+ >>> for number in my_range(100000000):
+ ... print(number)
+
+
+
ویژگیهای تابع Generator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-
-* تابع Generator یک تابع معمولی است که رفتاری مشابه با یک شی تکرارکننده (iterator) دارد.
* تابع Generator شامل یک یا چند دستور ``yield`` میباشد.
* در زمان فراخوانی تابع Generator، تابع اجرا نمیشود ولی در عوض یک شی از نوع ``generator`` برای آن تابع برگردانده میشود.
-* با استفاده از دستور ``yield`` میتوانیم در هر نقطهای از تابع Generator که بخواهیم توقف ایجاد کنیم - بدون از دست رفتن وضعیت فعلی تابع - و سپس با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) به ادامه روند اجرا برگردیم.
+* با استفاده از دستور ``yield`` میتوانیم در هر نقطهای از تابع Generator که بخواهیم توقف ایجاد کنیم و مقدار **yield (حاصل) شده** را با استفاده از متد ``()__next__`` (یا ``()next`` در پایتون 2x) دریافت نماییم.
-* با نخستین فراخوانی متد ``()__next__`` تابع اجرا میشود، تا زمانی که به یک دستور ``yield`` برسد. در این زمان دستور ``yield`` یک نتیجه تولید میکند و اجرای تابع متوقف میشود. با فراخوانی مجدد متد ``()__next__`` اجرای تابع از ادامه دستور ``yield`` سر گرفته میشود.
+* با نخستین فراخوانی متد ``()__next__`` تابع اجرا میشود، تا زمانی که به یک دستور ``yield`` برسد. در این زمان دستور ``yield`` یک نتیجه تولید میکند و اجرای تابع متوقف میشود. با فراخوانی مجدد متد ``()__next__`` اجرای تابع از ادامه همان دستور ``yield`` سر گرفته میشود.
* معمولا نیازی به استفاده مستقیم از متد ``()__next__`` نمیشود و توابع Generator از طریق دستورهایی به مانند ``for`` یا توابعی به مانند ``()sum`` و... که توانایی دریافت یک **دنباله** (Sequence) را دارند، مورد استفاده قرار میگیرند.
* در پایان تولید توابع Generator یک استثنا ``StopIteration`` در نقطه توقف خود گزارش میدهند که میبایست درون برنامه کنترل شود.
-* فراموش نکنیم که استفاده از دستور ``return`` در هر کجا از بدنه تابع باعث پایان یافتن اجرای تابع در آن نقطه میشود و توابع Generator نیز از این امر مسثنا نیستند .
+* فراموش نکنیم که استفاده از دستور ``return`` در هر کجا از بدنه تابع باعث پایان یافتن اجرای تابع در آن نقطه میشود و توابع Generator نیز از این امر مسثنا نیستند!.
@@ -299,7 +306,9 @@ Generator
>>>
-در ادامه Yield و Coroutines
+
+
+در ادامه Coroutine :yield
------------------------------------
From ac86e73d0109f9d5a80784c149f34a32668f486b Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Mon, 7 Oct 2019 01:07:38 +0330
Subject: [PATCH 008/294] start Coroutine
---
lessons/l13.rst | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index d0f2533..f9dab7e 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -311,6 +311,35 @@ Generator
در ادامه Coroutine :yield
------------------------------------
+از نسخه پایتون 2.5 ویژگیهای جدیدی به تابع Generator افزوده شد [`PEP 342 `__]. اگر داخل یک تابع، دستور ``yield`` را در سمت راست یک عملگر انتساب ``=`` قرار دهیم آنگاه تابع مذکور رفتار متفاوتی از خود نشان میدهد که باعث میشود به آن **Coroutine** گفته شود. تصور کنید که اکنون میتوانیم مقادیر دلخواه خود را به تابع Generator ارسال کنیم!::
+
+ >>> def receiver():
+ ... print("Ready to receive")
+ ... while True:
+ ... n = (yield)
+ ... print("Got %s" % n)
+ ...
+ >>>
+
+
+ >>> receiver_generator = receiver()
+
+ >>> receiver_generator.__next__()
+ Ready to receive
+
+ >>> receiver_generator.send('WooW!!')
+ Got WooW!!
+
+ >>> receiver_generator.send(1)
+ Got 1
+
+ >>> receiver_generator.send(':)')
+ Got :)
+
+چگونگی اجرای یک **Coroutine** همانند یک Generator است.
+
+
+
From e636707f96ea057c790498a7144c7739b39bf574 Mon Sep 17 00:00:00 2001
From: Saeid
Date: Mon, 7 Oct 2019 10:03:59 +0330
Subject: [PATCH 009/294] following Corotine
---
lessons/l13.rst | 64 ++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 61 insertions(+), 3 deletions(-)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index f9dab7e..1a03e32 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -311,7 +311,7 @@ Generator
در ادامه Coroutine :yield
------------------------------------
-از نسخه پایتون 2.5 ویژگیهای جدیدی به تابع Generator افزوده شد [`PEP 342 `__]. اگر داخل یک تابع، دستور ``yield`` را در سمت راست یک عملگر انتساب ``=`` قرار دهیم آنگاه تابع مذکور رفتار متفاوتی از خود نشان میدهد که باعث میشود به آن **Coroutine** گفته شود. تصور کنید که اکنون میتوانیم مقادیر دلخواه خود را به تابع Generator ارسال کنیم!::
+از نسخه پایتون 2.5 ویژگیهای جدیدی به تابع Generator افزوده شد [`PEP 342 `__]. اگر داخل یک تابع، دستور ``yield`` را در سمت راست یک عملگر انتساب ``=`` قرار دهیم آنگاه تابع مذکور رفتار متفاوتی از خود نشان میدهد که به آن در زبان برنامهنویسی پایتون **Coroutine** گفته شود. تصور کنید که اکنون میتوانیم مقادیر دلخواه خود را به تابع Generator ارسال کنیم!::
>>> def receiver():
... print("Ready to receive")
@@ -324,7 +324,7 @@ Generator
>>> receiver_generator = receiver()
- >>> receiver_generator.__next__()
+ >>> receiver_generator.__next__() # python 3.x - In Python 2.x use .next()
Ready to receive
>>> receiver_generator.send('WooW!!')
@@ -336,7 +336,65 @@ Generator
>>> receiver_generator.send(':)')
Got :)
-چگونگی اجرای یک **Coroutine** همانند یک Generator است.
+چگونگی اجرای یک **Coroutine** همانند یک Generator است ولی با این تفاوت که متد ``()send`` نیز برای ارسال مقدار به درون تابع در اختیار است.
+
+
+با فراخوانی تابع Coroutine، بدنه اجرا نمیشود بلکه یک شی از نوع Generator برگردانده میشود. متد ``()__next__`` (یا ``()next`` در پایتون 2x) اجرای برنامه را به نخستین ``yield`` میرساند، در این نقطه تابع در وضعیت تعلیق (Suspend) قرار میگیرد و آماده دریافت مقدار است. متد ``()send`` مقدار مورد نظر را به تابع ارسال میکند که این مقدار توسط عبارت ``(yield)`` در Coroutine دریافت میشود. پس از دریافت مقدار، اجرای Coroutine تا رسیدن به ``yield`` بعدی (در صورت وجود) یا انتهای بدنه تابع ادامه مییابد.
+
+در بحث Coroutineها برای رهایی از فراخوانی متد ``()__next__`` میتوان از Decoratorها استفاده کرد::
+
+
+ >>> def coroutine(func):
+ ... def start(*args,**kwargs):
+ ... generator = func(*args,**kwargs)
+ ... generator.__next__()
+ ... return generator
+ ... return start
+ ...
+ >>>
+ >>> @coroutine
+ ... def receiver():
+ ... print("Ready to receive")
+ ... while True:
+ ... n = (yield)
+ ... print("Got %s" % n)
+ ...
+ >>>
+ >>> receiver_generator = receiver()
+ >>> receiver_generator.send('Hello World') # Note : No initial .next()/.__next__() needed
+
+
+یک Coroutine میتواند به دفعات نامحدود اجرا شود مگر اینکه اجرای آن توسط برنامه با فراخوانی متد ``()close`` یا به خودی خود با پایان خطوط اجرای تابع، پایان بپذیرد.
+
+چنانچه پس از پایان Coroutine، متد ``()send`` فراخوانی شود یک استثنا ``StopIteration`` رخ خواهد داد::
+
+ >>> receiver_generator.close()
+ >>> receiver_generator.send('value')
+ Traceback (most recent call last):
+ File "", line 1, in
+ StopIteration
+
+
+یک Coroutine میتواند همزمان با دریافت مقدار، خروجی نیز تولید و برگرداند::
+
+ >>> def line_splitter(delimiter=None):
+ ... print("Ready to split")
+ ... result = None
+ ... while True:
+ ... line = (yield result)
+ ... result = line.split(delimiter)
+ ...
+ >>>
+ >>> splitter = line_splitter(",")
+ >>> splitter.__next__()
+ Ready to split
+ >>> splitter.send("A,B,C")
+ ['A', 'B', 'C']
+ >>> splitter.send("100,200,300")
+ ['100', '200', '300']
+ >>>
+
+**چه اتفاقی افتاد؟**
From b64b3ce408ca94fde8158d4aa85a92a0e47a4e91 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Tue, 8 Oct 2019 23:28:20 +0330
Subject: [PATCH 010/294] complete Coroutines
---
lessons/l13.rst | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index 1a03e32..f1c8ce5 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -311,7 +311,7 @@ Generator
در ادامه Coroutine :yield
------------------------------------
-از نسخه پایتون 2.5 ویژگیهای جدیدی به تابع Generator افزوده شد [`PEP 342 `__]. اگر داخل یک تابع، دستور ``yield`` را در سمت راست یک عملگر انتساب ``=`` قرار دهیم آنگاه تابع مذکور رفتار متفاوتی از خود نشان میدهد که به آن در زبان برنامهنویسی پایتون **Coroutine** گفته شود. تصور کنید که اکنون میتوانیم مقادیر دلخواه خود را به تابع Generator ارسال کنیم!::
+از نسخه پایتون 2.5 ویژگیهای جدیدی به تابع Generator افزوده شد [`PEP 342 `__]. اگر داخل یک تابع، دستور ``yield`` را در سمت راست یک عملگر انتساب ``=`` قرار دهیم آنگاه تابع مذکور رفتار متفاوتی از خود نشان میدهد که به آن در زبان برنامهنویسی پایتون **Coroutine** (کوروتین) گفته میشود. تصور کنید که اکنون میتوانیم مقادیر دلخواه خود را به تابع Generator ارسال کنیم!::
>>> def receiver():
... print("Ready to receive")
@@ -381,20 +381,35 @@ Generator
... print("Ready to split")
... result = None
... while True:
- ... line = (yield result)
+ ... line = yield result
... result = line.split(delimiter)
...
>>>
>>> splitter = line_splitter(",")
- >>> splitter.__next__()
+ >>>
+ >>> splitter.__next__() # python 3.x - In Python 2.x use .next()
Ready to split
+ >>>
>>> splitter.send("A,B,C")
['A', 'B', 'C']
+ >>>
>>> splitter.send("100,200,300")
['100', '200', '300']
>>>
-**چه اتفاقی افتاد؟**
+**چه اتفاقی افتاد؟!**
+
+تابع ``line_splitter`` با مقدار ورودی ``","`` فراخوانی میشود. همانطور که میدانیم در این لحظه تنها اتفاقی که میافتد ایجاد یک نمونه شی از نوع Generator خواهد بود (و هیچ یک از خطوط داخل بدنه تابع اجرا نخواهد شد). با فراخوانی متد ``()__splitter.__next`` بدنه تابع به اجرا درمیاید تا به نخستین ``yield`` برسد. یعنی عبارت ``"Ready to split"`` در خروجی چاپ، متغیر ``result`` با مقدار اولیه ``None`` تعریف و در نهایت با تایید شرط دستور ``while`` اجرا به سطر ``line = yield result`` میرسد. در این سطر بر اساس ارزیابی عبارت سمت راست عمل انتساب، مقدار متغیر ``result`` که برابر ``None`` است به خارج از تابع برگردانده و سپس تابع در وضعیت تعلیق (Suspend) قرار میگیرد. ولی باید توجه داشت که هنوز عمل انتساب در این سطر به صورت کامل به انجام نرسیده است!. در ادامه با فراخوانی متد ``("splitter.send("A,B,C``، رشته ``"A,B,C"`` در ``yield`` قرار داده میشود و اجرای برنامه از حالت تعلیق خارج و ادامه مییابد. مقدار ``yield`` به ``line`` انتساب داده میشود و اجرای سطر ``line = yield result`` کامل میشود. در سطر بعد، رشته درون متغیر ``line`` بر اساس ``delimiter`` که در ابتدا با ``","`` مقداردهی شده بود تفکیک و به متغیر ``result`` انتساب داده میشود (مقدار متغیر ``result`` که تا پیش از این برابر ``None`` بوده است تغییر میکند). با پایان خطوط بدنه و تایید دوباره درستی شرط دستور ``while``، بدنه آن یکبار دیگر اجرا میشود تا از نو به ``yield`` برسد یعنی به سطر ``line = yield result``. اکنون در بار دوم اجرای حلقه بر خلاف بار نخست مقدار متغیر ``result`` برابر با ``None`` نبوده و عمل yield آن یا همان بازگرداندن آن در خروجی قابل مشاهده خواهد بود یعنی مقدار ``['A', 'B', 'C']`` که در بار نخست اجرای حلقه تولید شده بود، اکنون در خروجی به نمایش در خواهد آمد و سپس تابع بار دیگر در حالت تعلیق قرار میگیرد (تابع منتظر فراخوانی یکی از متدهای ``()send`` یا ``()__next__`` یا ``()close`` میماند). روال کار با فراخوانی متد ``("splitter.send("100,200,300`` به همین صورت ادامه مییابد...
+
+در مورد سطر ``line = yield result``، میدانیم که برای انجام عمل انتساب ابتدا لازم است مقدار عبارت سمت راست ارزیابی و سپس به سمت چپ انتساب داده شود. یعنی مفسر پایتون ابتدا ``yield result`` را اجرا میکند که حاصل آن بازگرداندن مقدار متغیر ``result`` (در بار نخست اجرای حلقه = ``None``) به خارج تابع خواهد بود و سپس عبارت ``line = yield`` که مقدار ارسالی از متد ``()send`` را به متغیر ``line`` انتساب میدهد.
+
+|
+
+مبحث Coroutine گستردهتر از سطحی است که در این درس میتواند بیان شود ولی در این لحظه برای دریافت مثالها، کاربرد و جزییات بیشتر در موضوع Coroutine زبان برنامهنویسی پایتون، ارائه آقای David Beazley در کنفرانس PyCon'2009 میتواند مفید باشد.
+
+PDF: [`A Curious Course on Coroutines and Concurrency `__]
+
+VIDEO: [`YouTube `__]
From e952c7235ec28bd427442f0af6ac1195ee2d048f Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Mon, 14 Oct 2019 22:39:53 +0330
Subject: [PATCH 011/294] explain List Comprehensions
---
lessons/l13.rst | 95 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index f1c8ce5..69632ee 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -412,6 +412,101 @@ PDF: [`A Curious Course on Coroutines and Concurrency `__]
+List Comprehensions
+--------------------
+
+**List Comprehensions** به عملیاتی گفته میشود که در طی آن میتوان یک تابع را به تک تک اعضای یک نوع شی لیست (list) اعمال و نتیجه را در قالب یک نوع شی لیست جدید دریافت کرد [`PEP 202 `__]::
+
+ >>> numbers = [1, 2, 3, 4, 5]
+ >>> squares = [n * n for n in numbers]
+ >>>
+ >>> squares
+ [1, 4, 9, 16, 25]
+ >>>
+
+نمونه کد بالا برابر است با::
+
+ >>> numbers = [1, 2, 3, 4, 5]
+ >>> squares = []
+ >>> for n in numbers:
+ ... squares.append(n * n)
+ ...
+ >>>
+ >>> squares
+ [1, 4, 9, 16, 25]
+
+
+سینتکس کلی List Comprehensions به صورت زیر است::
+
+ [expression for item1 in iterable1 if condition1
+ for item2 in iterable2 if condition2
+ ...
+ for itemN in iterableN if conditionN]
+
+ # This syntax is roughly equivalent to the following code:
+
+ s = []
+ for item1 in iterable1:
+ if condition1:
+ for item2 in iterable2:
+ if condition2:
+ ...
+ for itemN in iterableN:
+ if conditionN: s.append(expression)
+
+
+به مثالهایی دیگر در این زمینه توجه نمایید::
+
+ >>> a = [-3,5,2,-10,7,8]
+ >>> b = 'abc'
+
+ >>> [2*s for s in a]
+ [-6, 10, 4, -20, 14, 16]
+
+ >>> [s for s in a if s >= 0]
+ [5, 2, 7, 8]
+
+ >>> [(x,y) for x in a for y in b if x > 0]
+ [(5, 'a'), (5, 'b'), (5, 'c'), (2, 'a'), (2, 'b'), (2, 'c'), (7, 'a'), (7, 'b'), (7, 'c'), (8, 'a'), (8, 'b'), (8, 'c')]
+
+ >>> import math
+ >>> c = [(1,2), (3,4), (5,6)]
+ >>> [math.sqrt(x*x+y*y) for x,y in c]
+ [2.23606797749979, 5.0, 7.810249675906654]
+
+
+توجه داشته باشید، چنانچه نتیجه اعمال List Comprehensions در هر نوبت شامل بیش از یک عضو باشد، میبایست مقادیر نتایج در داخل یک پرانتز قرار داده شوند (به صورت یک شی تاپل - tuple).
+
+به نمونه ``[x,y) for x in a for y in b if x > 0)]`` و خروجی آن توجه نمایید. با توجه به این موضوع عبارت زیر از نظر مفسر پایتون نادرست میباشد::
+
+ >>> [x,y for x in a for y in b]
+ File "", line 1
+ [x,y for x in a for y in b]
+ ^
+ SyntaxError: invalid syntax
+ >>>
+
+یک نکته مهم دیگر باقیمانده است. به نمونه کد پایین در دو نسخه پایتون 3x و 2x توجه نمایید::
+
+ # Python 3.x
+
+ >>> x = 'before'
+ >>> a = [x for x in (1, 2, 3)]
+ >>>
+ >>> x
+ 'before'
+
+::
+
+ # Python 2.x
+
+ >>> x = 'before'
+ >>> a = [x for x in (1, 2, 3)]
+ >>>
+ >>> x
+ 3
+
+هر دو کد یکسان هستند ولی در نسخه 2x به دلیل اینکه متغیرهای تکرار تعریف شده - در اینجا ``x`` - در یک حوزه (scope) جداگانه در نظر گرفته نمیشوند، با تغییر مقدار آنها در داخل عبارت، مقدار همنام موجود در حوزه بیرونی عبارت نیز تغییر داده میشود. این به بیان آقای روسوم "dirty little secret" در نسخه 3x برطرف گردیده است. [`توضیحات بیشتر `__]
From ce046d9e215fd50efd74ec86ac8151bc105e6a29 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Tue, 15 Oct 2019 21:54:11 +0330
Subject: [PATCH 012/294] explain Generator Expressions
---
lessons/l13.rst | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index 69632ee..efe21e1 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -508,6 +508,86 @@ List Comprehensions
هر دو کد یکسان هستند ولی در نسخه 2x به دلیل اینکه متغیرهای تکرار تعریف شده - در اینجا ``x`` - در یک حوزه (scope) جداگانه در نظر گرفته نمیشوند، با تغییر مقدار آنها در داخل عبارت، مقدار همنام موجود در حوزه بیرونی عبارت نیز تغییر داده میشود. این به بیان آقای روسوم "dirty little secret" در نسخه 3x برطرف گردیده است. [`توضیحات بیشتر `__]
+Generator Expressions
+----------------------
+
+عملکرد **Generator Expressions** مشابه **List Comprehensions** است ولی با خاصیت یک شی Generator و برای ایجاد آن کافی است به جای براکت ``[]`` در List Comprehensions از پرانتز ``()`` استفاده کنیم. [`PEP 289 `__]::
+
+ >>> a = [1, 2, 3, 4]
+ >>> b = (10*i for i in a)
+ >>>
+ >>>
+ >>> b
+ at 0x7f488703aca8>
+ >>>
+ >>> b.__next__() # python 3.x - In Python 2.x use .next()
+ 10
+ >>> b.__next__() # python 3.x - In Python 2.x use .next()
+ 20
+ >>>
+
+درک تفاوت Generator Expressions و List Comprehensions بسیار مهم است. خروجی یک **List Comprehensions** دقیقا همان نتیجه انجام عملیات در قالب یک شی لیست است در حالی که خروجی یک **Generator Expressions** شی است که میداند چگونه نتایج را مرحله به مرحله تولید کند. درک این دست موضوعات نقش مهمی در بالا بردن کارایی (Performance) برنامه و مصرف حافظه (Memory) خواهد داشت.
+
+با اجرای نمونه کد پایین؛ از میان تمام سطرهای داخل فایل The_Zen_of_Python.txt، سطرهایی که به صورت کامنت در زبان پایتون باشند چاپ میشوند:
+
+.. code-block:: text
+ :linenos:
+
+ Beautiful is better than ugly.
+ Explicit is better than implicit.
+ Simple is better than complex.
+ Complex is better than complicated.
+ Flat is better than nested.
+ Sparse is better than dense.
+ Readability counts.
+ Special cases aren't special enough to break the rules.
+ Although practicality beats purity.
+ Errors should never pass silently.
+ Unless explicitly silenced.
+ In the face of ambiguity, refuse the temptation to guess.
+ There should be one-- and preferably only one --obvious way to do it.
+ Although that way may not be obvious at first unless you're Dutch.
+ Now is better than never.
+ Although never is often better than *right* now.
+ If the implementation is hard to explain, it's a bad idea.
+ If the implementation is easy to explain, it may be a good idea.
+ Namespaces are one honking great idea -- let's do more of those!
+ ------------------------------------------------------------------
+ # File Name: The_Zen_of_Python.txt
+ # The Zen of Python
+ # PEP 20: https://www.python.org/dev/peps/pep-0020
+
+::
+
+ >>> file = open("/home/saeid/Documents/The_Zen_of_Python.txt")
+ >>> lines = (t.strip() for t in file)
+ >>> comments = (t for t in lines if t[0] == '#')
+ >>> for c in comments:
+ ... print(c)
+ ...
+ # File Name: The_Zen_of_Python.txt
+ # The Zen of Python
+ # PEP 20: https://www.python.org/dev/peps/pep-0020
+ >>>
+
+در سطر یکم، فایل The_Zen_of_Python.txt باز شده و در سطر دوم یک شی Generator برای دستیابی و strip کردن (حذف کاراکترهای خالی (space) احتمالی در ابتدا و انتهای متن سطر) آنها به شیوه **Generator Expressions** به دست آمده است. توجه داشته باشید که سطرهای فایل هنوز خوانده نشدهاند و تنها امکان درخواست و پیمایش سطر به سطر فایل ایجاد شده است. در سطر سوم با ایجاد یک شی Generator دیگر (باز هم به شیوه **Generator Expressions**) امکان فیلتر سطرهای کامنت مانند در داخل فایل را به کمک شی ``lines`` مرحله قبل، به دست آوردهایم. ولی هنوز سطرهای فایل خوانده نشدهاند چرا که هنوز درخواستی مبنی بر تولید به هیچ یک از دو شی Generator ایجاد شده (``lines`` و ``comments``) ارسال نشده است. تا اینکه بالاخره در سطر چهارم دستور حلقه ``for`` شی ``comments`` را به جریان میاندازد و این شی نیز بر اساس عملیات تعریف شده برای آن، شی ``lines`` را به جریان در میآورد.
+
+فایل The_Zen_of_Python.txt مورد استفاده در این مثال حجم بسیار کمی دارد ولی تاثیر به کار گرفتن **Generator Expressions** در این مثال را میتوانید با استخراج کامنتهای یک فایل چند گیگابایتی مشاهده نمایید!
+
+.. tip::
+ شی Generator ایجاد شده به شیوه **Generator Expressions** را نیز میتوان با استفاده از تابع ``()list`` به شی لیست تبدیل کرد::
+
+ >>> comment_list = list(comments)
+ >>> comment_list
+ ['# File Name: The_Zen_of_Python.txt',
+ '# The Zen of Python',
+ '# PEP 20: https://www.python.org/dev/peps/pep-0020']
+
+
+
+
+
+
From 0811a4e7fd2a8469cff21a727080e92fdfe4bde0 Mon Sep 17 00:00:00 2001
From: Saeid
Date: Fri, 18 Oct 2019 19:58:03 +0330
Subject: [PATCH 013/294] explain lambda
---
lessons/l13.rst | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index efe21e1..3e8d39b 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -585,6 +585,58 @@ Generator Expressions
+lambda و توابع ناشناس
+---------------------------
+
+در زبان برنامهنویسی پایتون توابع ناشناس (Anonymous functions) یا **Lambda functions** توابعی هستند که میتوانند هر تعداد آرگومان داشته باشند ولی بدنه آنها میبایست تنها شامل یک عبارت باشد. برای ساخت این دست توابع از کلمه کلیدی ``lambda`` استفاده میشود. الگوی ساختاری این نوع تابع به صورت زیر است::
+
+ lambda args : expression
+
+در این الگو ``args`` معرف هر تعداد آرگومان است که با استفاده از کاما (``,``) از یکدیگر جدا شدهاند و ``expression`` بیانگر تنها یک عبارت پایتونی است که شامل دستوراتی همچون ``for`` یا ``while`` نمیشود.
+
+
+به عنوان نمونه تابع پایین را در نظر بگیرید::
+
+ >>> def a_function(x, y):
+ ... return x + y
+ ...
+ >>>
+ >>> a_function(2, 3)
+ 5
+
+این تابع در فرم ناشناس به صورت زیر خواهد بود::
+
+ >>> a_function = lambda x,y : x+y
+ >>> a_function(2, 3)
+ 5
+
+یا::
+
+ >>> (lambda x,y: x+y)(2, 3)
+ 5
+
+
+**کاربرد اصلی Lambda functions کجاست؟**
+
+این دست توابع بیشتر در مواقعی که میخواهیم یک تابع کوتاه را به عنوان آرگومان به تابعی دیگر ارسال کنیم کاربرد دارند.
+
+برای نمونه از درس هشتم به یاد داریم که برای مرتبسازی اعضای یک شی لیست از متد ``()sort`` استفاده و بیان شد که متد ``()sort`` آرگومان اختیاری با نام ``key`` دارد که میتوان با ارسال یک تابع تک آرگومانی به آن عمل دلخواهی را بر روی تک تک عضوهای لیست مورد نظر، پیش از مقایسه و مرتبسازی به انجام رساند (به عنوان مثال: تبدیل حروف بزرگ به کوچک)::
+
+ >>> L = ['a', 'D', 'c', 'B', 'e', 'f', 'G', 'h']
+
+ >>> L.sort()
+
+ >>> L
+ ['B', 'D', 'G', 'a', 'c', 'e', 'f', 'h']
+
+ >>> L.sort(key=lambda n: n.lower())
+
+ >>> L
+ ['a', 'B', 'c', 'D', 'e', 'f', 'G', 'h']
+ >>>
+
+
+
From fe771fa57551df08417fe21b58a92847de4b58a7 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Sat, 19 Oct 2019 18:16:53 +0330
Subject: [PATCH 014/294] review Decorator
---
lessons/l13.rst | 122 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 120 insertions(+), 2 deletions(-)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index 3e8d39b..f59e98a 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -8,7 +8,7 @@
درس ۱۳: تابع - بخش دوم
========================
-
+این درس در ادامه درس پیش است که به معرفی مواردی از کاربردهای تابع در ایجاد مفاهیمی جدید، مهم و کاربردی در زبان برنامهنویسی پایتون میپردازد. مبحث تابع در پایتون با این درس به پایان نمیرسد و نکات باقیمانده در درس بعدی ارائه میشوند.
@@ -32,7 +32,7 @@ Decorator
----------
-دکوراتور (تزئینگر) یا همان **Decorator** ها [`PEP 318 `__] به توابعی گفته میشود که به منظور پوشش (wrap) توابع یا کلاسهای دیگر پیادهسازی میشوند. Decoratorها در پایتون ابزار بسیار کاربردی و مفیدی هستند که به برنامهنویس این امکان را میدهند تا با کاهش حجم کدنویسی و بدون تغییر در بدنه توابع و کلاسهای خود، رفتار و ویژگیهای آنها را گسترش دهد. در این بخش تمرکز بر روی اعمال Decoratorها به توابع است و Decorator کلاس را در درس مربوط به کلاسها بررسی خواهیم کرد.
+دکوراتور (تزئینگر) یا همان **Decorator** ها [`PEP 318 `__] به توابعی گفته میشود که به منظور پوشش (wrap) توابع یا کلاسهای دیگر پیادهسازی میشوند. Decoratorها در پایتون ابزار بسیار کاربردی و مفیدی هستند که به برنامهنویس این امکان را میدهند تا با کاهش حجم کدنویسی و بدون تغییر در بدنه توابع و کلاسهای خود، رفتار و ویژگیهای آنها را گسترش دهد. در این بخش تمرکز بر روی **اعمال** Decoratorها به **توابع** است و Decorator کلاس را در درس مربوط به کلاسها بررسی خواهیم کرد.
برای پوشش یک تابع توسط Decorator از سینتکسی مشابه ``decorator_name@`` در بالای بخش سرآیند استفاده میشود:
@@ -198,6 +198,124 @@ Decorator
>>>
+**functools.wraps@**
+======================
+
+در پایتون عنوانی مطرح است به نام **Higher-order functions** (توابع مرتبه بالاتر) و به توابعی گفته میشود که اعمالی را روی توابع دیگر انجام میدهند یا یک تابع جدید را به عنوان خروجی برمیگرداند. بر همین اساس یک ماژول به نام ``functools`` نیز در کتابخانه استاندارد پایتون قرار گرفته است که یک سری توابع کمکی و کاربردی ارائه میدهد [`مستندات پایتون `__]. یکی از این توابع ``wraps`` [`مستندات پایتون `__] میباشد.
+
+اما چرا معرفی این تابع در این بخش مهم است؟. وقتی ما از یک Decorator استفاده میکنیم، اتفاقی که میافتد این است که یک تابع جدید جایگزین تابع اصلی ما میشود. به نمونه کدهای پایین توجه نمایید::
+
+ >>> def func(x):
+ ... """does some math"""
+ ... return x + x * x
+ ...
+ >>>
+ >>> print(func.__name__)
+ func
+ >>> print(func.__doc__)
+ does some math
+ >>>
+
+::
+
+ >>> def logged(func):
+ ... def with_logging(*args, **kwargs):
+ ... print(func.__name__ + " was called")
+ ... return func(*args, **kwargs)
+ ... return with_logging
+ ...
+ >>>
+ >>> @logged
+ ... def f(x):
+ ... """does some math"""
+ ... return x + x * x
+ ...
+ >>>
+ >>> print(f.__name__)
+ with_logging
+ >>> print(f.__doc__)
+ None
+ >>>
+
+::
+
+ >>> # It is mean: f = logged(func)
+ ...
+ >>> f = logged(func)
+ >>> print(f.__name__)
+ with_logging
+
+در زمان استفاده Decorator وقتی خواستیم نام تابع را چاپ کنیم ``(__print(f.__name`` نام تابع جدید (``with_logging``) چاپ شد و نه تابع اصلی (``f``).
+
+استفاده از Decorator همیشه به معنی از دست رفتن اطلاعات مربوط به تابع اصلی است که به منظور جلوگیری از این اتفاق و حفظ اطلاعات مربوط به تابع اصلی خود میتوانیم از تابع ``wraps`` استفاده کنیم. این تابع در واقع خود یک Decorator است که وظیفه آن کپی اطلاعات از تابعی که به عنوان آرگومان دریافت میکند به تابعی که به آن انتساب داده شده است::
+
+ >>> from functools import wraps
+ >>>
+ >>> def logged(func):
+ ... @wraps(func)
+ ... def with_logging(*args, **kwargs):
+ ... print(func.__name__ + " was called")
+ ... return func(*args, **kwargs)
+ ... return with_logging
+ ...
+ >>>
+ >>> @logged
+ ... def f(x):
+ ... """does some math"""
+ ... return x + x * x
+ ...
+ >>>
+ >>> print(f.__name__)
+ f
+ >>> print(f.__doc__)
+ does some math
+ >>>
+
+
+
+
+
+
+
+
+
+
+لطفا به آخرین مثال از بحث Decorator نیز توجه فرمایید. در این مثال زمان اجرای یک تابع را با استفاده از Decoratorها محاسبه خواهیم کرد [`منبع `__]::
+
+ >>> import functools
+ >>> import time
+ >>>
+ >>> def timer(func):
+ ... """Print the runtime of the decorated function"""
+ ... @functools.wraps(func)
+ ... def wrapper_timer(*args, **kwargs):
+ ... start_time = time.perf_counter()
+ ... value = func(*args, **kwargs)
+ ... end_time = time.perf_counter()
+ ... run_time = end_time - start_time
+ ... print(f"Finished {func.__name__!r} in {run_time:.4f} secs")
+ ... return value
+ ... return wrapper_timer
+ ...
+ >>>
+ >>> @timer
+ ... def waste_some_time(num_times):
+ ... result = 0
+ ... for _ in range(num_times):
+ ... for i in range(10000)
+ ... result += i**2
+ ...
+ >>>
+ >>> waste_some_time(1)
+ Finished 'waste_some_time' in 0.0072 secs
+ >>> waste_some_time(999)
+ Finished 'waste_some_time' in 2.6838 secs
+
+در این مثال از تابع ``perf_counter`` برای محاسبه فواصل زمانی (time intervals) [`مستندات پایتون `__] استفاده شده که تنها از نسخه 3.3 به بعد در دسترس میباشد [`اطلاعات تکمیلی `__].
+
+چنانچه درک دستور ``("print(f"Finished {func.__name__!r} in {run_time:.4f} secs`` برایتان مبهم است به درس هفتم بخش مربوط به رشتهها مراجعه نمایید.
+
+
Generator
----------
From 1754c2a080829b4ab607ec527f975e65a8a253f8 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Sat, 19 Oct 2019 18:51:30 +0330
Subject: [PATCH 015/294] =?UTF-8?q?review=20Generator=E2=80=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
lessons/l13.rst | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index f59e98a..b770895 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -398,6 +398,8 @@ Generator
* فراموش نکنیم که استفاده از دستور ``return`` در هر کجا از بدنه تابع باعث پایان یافتن اجرای تابع در آن نقطه میشود و توابع Generator نیز از این امر مسثنا نیستند!.
+* با فراخوانی متد ``close`` میتوانید یک شی Generator را خاموش کنید!. توجه داشته باشید که پس از فراخوانی این متد چنانچه باز هم درخواست ایجاد مقدار ارسال (``()__next__``) شود یک استثنا ``StopIteration`` گزارش میگردد.
+
به یک نمونه کد دیگر نیز توجه نمایید::
@@ -422,6 +424,26 @@ Generator
>>> countdown_generator.__next__()
7
>>>
+ >>> countdown_generator.close()
+ >>>
+ >>> countdown_generator.__next__()
+ Traceback (most recent call last):
+ File "", line 1, in
+ StopIteration
+ >>>
+
+
+.. tip::
+ شی Generator را میتوان با استفاده از تابع ``()list`` به شی لیست تبدیل کرد::
+
+ >>> countdown_list = list(countdown(10))
+ Counting down from 10
+ >>>
+ >>> countdown_list
+ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
+ >>>
+
+
From 70dfe987987bac894f27e2b6ea19ae77e7f4724e Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Sat, 19 Oct 2019 19:10:30 +0330
Subject: [PATCH 016/294] fix some sentence
---
lessons/l13.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index b770895..e4650c6 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -199,11 +199,11 @@ Decorator
**functools.wraps@**
-======================
+~~~~~~~~~~~~~~~~~~~~~
-در پایتون عنوانی مطرح است به نام **Higher-order functions** (توابع مرتبه بالاتر) و به توابعی گفته میشود که اعمالی را روی توابع دیگر انجام میدهند یا یک تابع جدید را به عنوان خروجی برمیگرداند. بر همین اساس یک ماژول به نام ``functools`` نیز در کتابخانه استاندارد پایتون قرار گرفته است که یک سری توابع کمکی و کاربردی ارائه میدهد [`مستندات پایتون `__]. یکی از این توابع ``wraps`` [`مستندات پایتون `__] میباشد.
+در پایتون عنوانی مطرح است به نام **Higher-order functions** (توابع مرتبه بالاتر) و به توابعی گفته میشود که اعمالی را روی توابع دیگر انجام میدهند یا یک تابع جدید را به عنوان خروجی برمیگرداند. بر همین اساس یک ماژول به نام ``functools`` نیز در کتابخانه استاندارد پایتون قرار گرفته است که یک سری توابع کمکی و کاربردی برای این دست توابع ارائه میدهد [`مستندات پایتون `__]. یکی از توابع داخل این ماژول ``wraps`` [`مستندات پایتون `__] میباشد.
-اما چرا معرفی این تابع در این بخش مهم است؟. وقتی ما از یک Decorator استفاده میکنیم، اتفاقی که میافتد این است که یک تابع جدید جایگزین تابع اصلی ما میشود. به نمونه کدهای پایین توجه نمایید::
+**اما چرا معرفی این تابع در این بخش مهم است؟** وقتی ما از یک Decorator استفاده میکنیم، اتفاقی که میافتد این است که یک تابع جدید جایگزین تابع اصلی ما میشود. به نمونه کدهای پایین توجه نمایید::
>>> def func(x):
... """does some math"""
From 474b628aa4030056b60baef72771a0d343938782 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Sat, 19 Oct 2019 19:44:45 +0330
Subject: [PATCH 017/294] a little explanation of the return statement
---
lessons/l12.rst | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/lessons/l12.rst b/lessons/l12.rst
index 68e709c..c9247ab 100644
--- a/lessons/l12.rst
+++ b/lessons/l12.rst
@@ -2,7 +2,7 @@
.. meta::
:description: کتاب آنلاین و آزاد آموزش زبان برنامهنویسی پایتون به فارسی - درس دوازدهم تابع
- :keywords: آموزش, آموزش پایتون, آموزش برنامه نویسی, پایتون, انواع شی, انواع داده, پایتون
+ :keywords: آموزش, آموزش پایتون, آموزش برنامه نویسی, پایتون,تابع, پایتون
درس ۱۲: تابع - بخش یکم
@@ -38,7 +38,7 @@
رویکرد این آموزش به تابع بر اساس برنامهنویسی اعلانی است. زبان پایتون قابلیت برنامهنویسی تابعی را نیز در کنار رویکردهای دیگر همچون اعلانی یا شیگرایی ارایه میدهد. برای چگونگی برنامهنویسی تابعی با استفاده از زبان پایتون میتوانید به کتاب Functional Programming in Python از انتشارات O'Reilly مراجعه نمایید (`دریافت نسخه pdf - رایگان `__).
-در کنار اصطلاح تابع در برنامهنویسی، اصطلاح مشابه دیگری نیز به عنوان «رِوال» (Procedure) وجود دارد. روال و تابع در ساختار شبیه یکدیگر هستند با این تفاوت که روالها مقداری برنمیگردانند. در پایتون سینتکسی برای تعریف روال وجود ندارد ولی به توابعی که مقداری برنمیگردانند، روال نیز گفته میشوند.
+در کنار اصطلاح تابع در برنامهنویسی، اصطلاح مشابه دیگری نیز به عنوان «رِوال» (Procedure) وجود دارد. روال و تابع در ساختار شبیه یکدیگر هستند با این تفاوت که روالها مقداری برنمیگردانند. در پایتون سینتکسی برای تعریف روال وجود ندارد ولی به توابعی که مقداری برنمیگردانند، روال نیز گفته میشوند که اشتباه است چرا که توابع در پایتون تحت هر شرایطی یک مقدار برمیگردانند حتی اگر این مقدار ``None`` باشد.
سینتکس
--------
@@ -89,6 +89,28 @@
8
>>>
+.. tip::
+
+ چنانچه در انتهای تابع دستور ``return`` نوشته نشود، مفسر پایتون به صورت ضمنی دستور ``return None`` را در نظر میگیرد. بنابراین با فراخوانی این چنین توابع در زبان پایتون، پس از اجرای کامل دستورات داخل بدنه مقدار ``None`` بازگردانده خواهد شد (`albeit a rather boring one `__).
+
+.. tip::
+ پیشنهاد `PEP 8 `__: در بازگردان مقدار در تابع یکنواخت عمل کنید. اگر از دستورات مرکبی به مانند ``if/else`` استفاده میکنید یا باید هیچ یک از بخشها به صراحت ``return`` نداشته باشند یا اگر لازم است حداقل یک بخش مقداری را برگرداند، باقی بخشها نیز میبایست یک مقداری را برگردانند حتی اگر قرار باشد این مقدار ``None`` در نظر گرفته شود::
+
+ YES:
+
+ def foo(x):
+ if x >= 0:
+ return math.sqrt(x)
+ else:
+ return None
+
+
+ NO:
+
+ def foo(x):
+ if x >= 0:
+ return math.sqrt(x)
+
در زبان برنامه نویسی پایتون تابع یک موجودیت **”first-class“** است که یعنی تابع را میتوان مانند دیگر اشیا به صورت پویا ایجاد یا نابود کرد، به صورت آرگومان به توابع دیگر ارسال نمود، به عنوان نتیجه توسط ``return`` بازگرداند و... در نتیجه میتوان یک تابع را درون بدنه دستورات کنترلی (``while`` ،``if`` و...) یا درون بدنه تابعی دیگر تعریف نمود::
>>> def outer(num1):
From 02a19f151a5e56b15a2663884140742eef314b20 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Sat, 19 Oct 2019 20:52:34 +0330
Subject: [PATCH 018/294] change format & add new
---
donate.rst | 104 +++++++++++++++++++++++++++++++++++++----------------
1 file changed, 74 insertions(+), 30 deletions(-)
diff --git a/donate.rst b/donate.rst
index 5db0d5c..7b6f1a6 100644
--- a/donate.rst
+++ b/donate.rst
@@ -9,7 +9,9 @@
گزارش هدایای پرداخت شده
=========================
-مبالغ مهم نیستند، از اقدام شما دوستان بسیار سپاسگذارم.
+مبالغ مهم نیستند، از اقدام و پیام تشویق شما دوستان بسیار سپاسگذارم. (*اطلاعات این صفحه به صورت آنی بروز نمیشود!*)
+
+----
|
@@ -20,172 +22,214 @@
+
+
+
.. raw:: html
- 26: 50,000 تومان در زمان 16:52 28-03-1398
+ 29: 20,000 تومان در زمان 11:41 03-06-1398
ممنون از زحمات شما
----
+
+
.. raw:: html
- 25: 50,000 تومان در زمان 09:13 08-02-1398
+ 28: 5,000 تومان در زمان 13:10 02-06-1398
متشکرم که دانشتون رو در اختیار ما می زارید.
----
+
.. raw:: html
- 24: 50,000 تومان در زمان 22:44 26-01-1398
+ 27: 1,000,000 تومان در زمان 22:23 11-04-1398
Omidvaram tashvighi beshe vase sorato detaile bishtar!
----
-سال 1397: 92,000 تومان
+
+.. raw:: html
+
+ 26: 50,000 تومان در زمان 16:52 28-03-1398
وسع یه دانشجو همینقدره ببخشید. کاش تا جایی که میتونین وب سایتو رایگان نگه دارین...
----
.. raw:: html
- 23: 5,000 تومان در زمان 13:52 23-11-1397
+ 25: 50,000 تومان در زمان 09:13 08-02-1398
با تشکر
----
.. raw:: html
- 22: 5,000 تومان در زمان 09:13 05-11-1397
+ 24: 50,000 تومان در زمان 22:44 26-01-1398
آقا برای آموزش پایتون خیلی زحمت کشیدی، مرسی.
+
+----
+
+|
+
+**سال 1397: 92,000 تومان**
+
+|
+
+
----
.. raw:: html
- 21: 10,000 تومان در زمان 15:25 01-11-1397
+ 23: 5,000 تومان در زمان 13:52 23-11-1397
از کتاب آموزش پایتون شما لذت بردم، درس اول و دوم رو خوندم. موفق و پیروز باشید.
----
.. raw:: html
- 20: 2,000 تومان در زمان 20:36 20-10-1397
+ 22: 5,000 تومان در زمان 09:13 05-11-1397
ممنون از کار بسیار مفید شما
----
.. raw:: html
- 19: 1,000 تومان در زمان 13:47 13-10-1397
+ 21: 10,000 تومان در زمان 15:25 01-11-1397
تشکر
----
.. raw:: html
- 18: 1,000 تومان در زمان 09:35 28-07-1397
+ 20: 2,000 تومان در زمان 20:36 20-10-1397
omid
----
.. raw:: html
- 17: 1,000 تومان در زمان 18:39 20-07-1397
+ 19: 1,000 تومان در زمان 13:47 13-10-1397
با سلام خیلی خوشحال شدم از مطالب خوبت. امیدوارم ادامه بدی ممنونم مجید
----
.. raw:: html
- 16: 25,000 تومان در زمان 16:45 10-06-1397
+ 18: 1,000 تومان در زمان 09:35 28-07-1397
salam
----
.. raw:: html
- 15: 2,000 تومان در زمان 12:45 24-05-1397
+ 17: 1,000 تومان در زمان 18:39 20-07-1397
خوب بود
----
.. raw:: html
- 14: 20,000 تومان در زمان 19:50 08-04-1397
+ 16: 25,000 تومان در زمان 16:45 10-06-1397
با تشکر
----
.. raw:: html
- 13: 10,000 تومان در زمان 22:27 04-04-1397
+ 15: 2,000 تومان در زمان 12:45 24-05-1397
با تشکر از کتاب روان و جامع شما
----
.. raw:: html
- 12: 10,000 تومان در زمان 18:30 26-02-1397
+ 14: 20,000 تومان در زمان 19:50 08-04-1397
.لطفا ادامه پایتون را هم تکمیل کنید
----
-سال 1396: 61,000 تومان
+.. raw:: html
+
+ 13: 10,000 تومان در زمان 22:27 04-04-1397
Awesome work! continue it!
+
+----
+
+.. raw:: html
+
+ 12: 10,000 تومان در زمان 18:30 26-02-1397
تشکر از نوشته بسیار خوبتان
+
+----
+
+|
+
+**سال 1396: 61,000 تومان**
+
+|
----
.. raw:: html
- 11: 5,000 تومان در زمان 17:51 06-12-1396
+ 11: 5,000 تومان در زمان 17:51 06-12-1396
هدیه :)
----
.. raw:: html
- 10: 10,000 تومان در زمان 21:23 10-09-1396
+ 10: 10,000 تومان در زمان 21:23 10-09-1396
بهترین سایت پایتون هستید چقدر بدبختی کشیدم بدون شما. شرمنده فعلا کمه جبران میکنم بیشتر
----
.. raw:: html
- 9: 5,000 تومان در زمان 21:00 07-09-1396
+ 9: 5,000 تومان در زمان 21:00 07-09-1396
👍
----
.. raw:: html
- 8: 10,000 تومان در زمان 08:39 06-08-1396
+ 8: 10,000 تومان در زمان 08:39 06-08-1396
مرسی از آقا سعید عزیز برای این کار با ارزش. ارزش این کارتون هیچ جوره با قابل پرداخت نیست.
----
.. raw:: html
- 7: 10,000 تومان در زمان 13:50 13-07-1396
+ 7: 10,000 تومان در زمان 13:50 13-07-1396
لطفا ادامه بدید
----
.. raw:: html
- 6: 1,000 تومان در زمان 10:04 11-06-1396
+ 6: 1,000 تومان در زمان 10:04 11-06-1396
ببخشید کمه ولی ایشالا بعد بیشتر
----
.. raw:: html
- 5: 10,000 تومان در زمان 22:44 16-04-1396
+ 5: 10,000 تومان در زمان 22:44 16-04-1396
مبلغی ناچیز و ناقابل بابت زحماتی که درآموزش پایتون میکشید
----
.. raw:: html
- 4: 10,000 تومان در زمان 17:51 11-04-1396
+ 4: 10,000 تومان در زمان 17:51 11-04-1396
بخاطر کارهای خوب در نگارش دقیق آموزش پایتُن
----
-سال 1395: 18,000 تومان
+|
+
+**سال 1395: 18,000 تومان**
+
+|
+
----
.. raw:: html
- 3: 10,000 تومان در زمان 19:33 27-11-1395
+ 3: 10,000 تومان در زمان 19:33 27-11-1395
کارتون عالیه، ادامه بدید.
----
.. raw:: html
- 2: 5,000 تومان در زمان 20:51 15-11-1395
+
+ 2: 5,000 تومان در زمان 20:51 15-11-1395
با تشکر از زحمات شما برای نشر علم .هر چند این مبالغ در برابر تلاش شما ناچیز است .
+
----
.. raw:: html
- 1: 3,000 تومان در زمان 11:27 09-11-1395
+ 1: 3,000 تومان در زمان 11:27 09-11-1395
دم شما گرم
From 9e53dfc295972aad7719d7e4a220a042dc0bf911 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Sat, 19 Oct 2019 21:12:54 +0330
Subject: [PATCH 019/294] start f-string
---
lessons/l07.rst | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/lessons/l07.rst b/lessons/l07.rst
index a5d54d4..b6fbef0 100644
--- a/lessons/l07.rst
+++ b/lessons/l07.rst
@@ -1414,6 +1414,51 @@
>>> '{0:{fill}{align}16}'.format(text, fill=align, align=align)
'>>>>>>>>>>>Right'
+
+f-string
+~~~~~~~~~~
+
+از نسخه پایتون 3.6 یک امکان جدید و بسیار جالب در مورد بحث قالببندی رشتهها ارايه شده است که با عنوان ``f-string`` شناخته میشود [`PEP 498 `__].
+
+ساختار همان ساده شده حالت ``()str.format`` میباشد::
+
+ >>> name = "Saeid"
+ >>> age = 32
+ >>> f"Hello, {name}. You are {age}."
+ 'Hello, Saeid. You are 32.'
+ >>>
+
+یعنی اگر در ابتدای یک متن، حرف ``f`` یا ``F`` قرار دهیم، آنگاه میتوانیم متغیرها یا عبارات خود را مستقیم در داخل آن - با استفاده از ``{}`` - قرار بدهیم::
+
+ >>> f"{2 * 37}"
+ '74'
+
+در نمونه کد پایین یک تابع را مستقیم در داخل متن موجود فراخوانی میکینم::
+
+ >>> def to_lowercase(input):
+ ... return input.lower()
+ ...
+ >>>
+ >>> name = "Eric Idle"
+ >>>
+ >>> f"{to_lowercase(name)} is funny."
+ 'eric idle is funny.'
+
+::
+
+ >>> f"{name.lower()} is funny."
+ 'eric idle is funny.'
+ >>>
+
+
+
+
+
+
+
+
+
+
.. rubric:: برخی از متدهای کاربردی یک شی رشته
* ``()capitalize`` [`اسناد پایتون `__] - یک کپی از رشته که نخستین حرف آن به صورت بزرگ (Capital) نوشته شده است را برمیگرداند::
From 295e922638ad4d0b119518f77a8fdf177c7bada1 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Sat, 19 Oct 2019 21:15:44 +0330
Subject: [PATCH 020/294] remove a ref to l07 - temp
---
lessons/l13.rst | 1 -
1 file changed, 1 deletion(-)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index e4650c6..9c7c081 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -313,7 +313,6 @@ Decorator
در این مثال از تابع ``perf_counter`` برای محاسبه فواصل زمانی (time intervals) [`مستندات پایتون `__] استفاده شده که تنها از نسخه 3.3 به بعد در دسترس میباشد [`اطلاعات تکمیلی `__].
-چنانچه درک دستور ``("print(f"Finished {func.__name__!r} in {run_time:.4f} secs`` برایتان مبهم است به درس هفتم بخش مربوط به رشتهها مراجعه نمایید.
Generator
From dbb7790a049779b65464e748e90ce3360a68853c Mon Sep 17 00:00:00 2001
From: Saeid
Date: Sun, 20 Oct 2019 10:14:28 +0330
Subject: [PATCH 021/294] explain f-string
---
lessons/l07.rst | 67 +++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 57 insertions(+), 10 deletions(-)
diff --git a/lessons/l07.rst b/lessons/l07.rst
index b6fbef0..3f3b3e3 100644
--- a/lessons/l07.rst
+++ b/lessons/l07.rst
@@ -893,7 +893,8 @@
-.. rubric:: دنبالهها
+رشته به عنوان دنباله (Sequence)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
برخی از انواع شی پایتون به مانند رشته، تاپل (tuple)، لیست (list) و... با عنوان **دنباله** (Sequence) نیز شناخته میشوند. دنباله ویژگیهایی دارد که در اینجا به کمک نوع رشته بررسی خواهیم کرد. رشته در واقع یک **دنباله** از کاراکترهاست در نتیجه میتوان هر یک از اعضای این دنباله را با استفاده از اندیس (Index) موقعیت آن دستیابی نمود؛ اندیس اعضا از سمت چپ با عدد صفر شروع و به سمت راست یک واحد یک واحد افزایش مییابد. به عنوان نمونه برای شی ``'Python Strings'`` میتوانیم شمای اندیسگذاری را به صورت پایین در نظر بگیریم::
@@ -960,7 +961,8 @@
TypeError: 'str' object does not support item assignment
-.. rubric:: عملگرها برای رشته
+عملگرها برای رشته
+~~~~~~~~~~~~~~~~~~~~
با رشتهها نیز میتوان از عملگرهای ``+`` (برای پیوند رشتهها) و ``*`` (برای تکرار رشتهها) بهره برد::
@@ -1000,7 +1002,8 @@
کمی جلوتر خواهید دید که از عملگر ``%`` نیز برای قالببندی رشتهها استفاده میگردد.
-.. rubric:: کاراکترهای Escape
+کاراکترهای Escape
+~~~~~~~~~~~~~~~~~~
به صورت پیشفرض تعدادی کاراکتر خاص تعریف شده است که میتوان آنها را درون رشتهها بکار برد. تمام این کاراکترها با یک ``\`` آغاز میشوند به همین دلیل گاهی نیز به نام Backslash Characters خوانده میشوند. در واقع این کاراکترها امکانی برای درج برخی دیگر از کاراکترها هستند که نمیتوان آنها را به سادگی توسط صفحهکلید وارد کرد. برای نمونه یکی از کاراکترهای Escape رایج ``n\`` است که بیانگر کاراکتری با کد اسکی 10 (LF) به نام newline میباشد؛ ``n\`` در هر جایی از رشته (یا متن) که درج گردد در هنگام چاپ سطر جاری را پایان میدهد و ادامه رشته (یا متن) از سطر جدید آغاز میشود [`اسناد پایتون `__]::
@@ -1040,7 +1043,8 @@
C:\new\text\sample.txt
-.. rubric:: تبدیل کد به کاراکتر و برعکس
+تبدیل کد به کاراکتر و برعکس
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
میدانیم برای اینکه کامپیوتر بتواند کاراکترها را درک کند نیاز به سیستمهایی است که آنها را برای تبدیل به کدهای پایه دو کدگذاری کند؛ به مانند سیستم اَسکی (ASCII) یا سیستمهای جامعتری مانند UTF-8 که تحت استاندارد یونیکد (Unicode) در دسترس است. گاهی نیاز است به این کدها دسترسی داشته باشیم و با کاراکترها بر اساس آنها کار کنیم؛ برای این منظور در پایتون میتوان از دو تابع ``()ord`` (تبدیل کد به کاراکتر) [`اسناد پایتون `__] و ``()chr`` (تبدیل کاراکتر به کد) [`اسناد پایتون `__] استفاده کرد. تابع ``()ord`` یک رشته تک کاراکتری را گرفته و یک عدد (در پایه ده) که بیانگر کد کاراکتر مورد نظر میباشد را برمیگرداند. تابع ``()chr`` نیز کد کاراکتری (که میبایست عددی در پایه ده باشد) را گرفته و کاراکتر مربوط به آن را برمیگرداند::
@@ -1087,7 +1091,8 @@
-.. rubric:: تبدیل به نوع رشته
+تبدیل به نوع رشته
+~~~~~~~~~~~~~~~~~~~~
برای تبدیل اشیایی از نوع دیگر به نوع رشته؛ کلاس ``()str`` [`اسناد پایتون `__] و تابع ``()repr`` [`اسناد پایتون `__] وجود دارد. کلاس ``()str`` یک نمونه غیر رسمی (informal) از نوع شی رشته را برمیگرداند؛ غیر رسمی از این جهت که توسط آن جزییات شی رشته پنهان میشود. اما تابع ``()repr`` یک نمونه رسمی (official) از نوع رشته پایتون را برمیگرداند. کمی قبلتر راجب تفاوت خروجی ``print`` و حالت تعاملی صحبت کردیم؛ در واقع خروجی ``()str`` مناسب برای چاپ است و همانند ``print`` جزییات این نوع شی را ارایه نمیدهد در حالی که ``()repr`` به مانند حالت تعاملی یک ارايه (representation) کامل از شی رشته را برمیگرداند::
@@ -1122,7 +1127,8 @@
'10'
-.. rubric:: قالببندی رشته (String Formatting)
+قالببندی رشته (String Formatting)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
قالببندی امکانی برای جایگزین کردن یک یا چند مقدار (به بیان بهتر: شی) - گاهی همراه با اعمال تغییر دلخواه - درون یک رشته است که به دو شکل در پایتون پیادهسازی میگردد [`اسناد پایتون `__]:
@@ -1418,7 +1424,7 @@
f-string
~~~~~~~~~~
-از نسخه پایتون 3.6 یک امکان جدید و بسیار جالب در مورد بحث قالببندی رشتهها ارايه شده است که با عنوان ``f-string`` شناخته میشود [`PEP 498 `__].
+از نسخه پایتون 3.6 یک امکان جدید و بسیار جالب در بحث قالببندی رشتهها ارايه شده است که با عنوان ``f-string`` شناخته میشود [`PEP 498 `__].
ساختار همان ساده شده حالت ``()str.format`` میباشد::
@@ -1433,7 +1439,43 @@ f-string
>>> f"{2 * 37}"
'74'
-در نمونه کد پایین یک تابع را مستقیم در داخل متن موجود فراخوانی میکینم::
+بدیهی است که متغیرها (- یا نتیجه حاصل عبارات) یا اشیای مورد استفاده در شیوه **f-string** در نهایت برای قرار گرفتن درون متن یا رشته مورد نظر میبایست به نوع رشته تبدیل شوند. در این شیوه به صورت پیشفرض متد ``()__str__`` برای تبدیل به نوع رشته فراخوانی میشود ولی میتوان با قرار دادن نشانگر ``r!`` در انتهای شی مورد نظر، تعیین کرد که متد ``()__repr__`` فراخوانی شود::
+
+ >>> name = 'Saeid'
+ >>> print(f'My name is {name}')
+ My name is Saeid
+ >>> print(f'My name is {name!r}')
+ My name is 'Saeid'
+ >>>
+
+در این شیوه میتوان از نماد ``{}`` در خارج از اصول قالببندی استفاده کرد ولی باید توجه داشت که هر دو نماد ``{{}}`` به عنوان یک ``{}`` در نظر گرفته میشود. وجود سه ``{{{}}}`` نیز در حکم همان دو تا میباشد::
+
+ >>> f'{{{{32}}}}'
+ '{{32}}'
+ >>> f'{{{32}}}'
+ '{32}'
+ >>> f'{{32}}'
+ '{32}'
+ >>> f'{32}'
+ '32'
+
+::
+
+ >>> print(f'{{My name}} is {name}')
+ {My name} is Saeid
+
+ >>> print(f'{{My name}} is {{name}}') # NOTE!
+ {My name} is {name}
+
+ >>> print(f'{{My name}} is {{{name}}}')
+ {My name} is {Saeid}
+
+ >>> print(f'{{My name}} is {{{{name}}}}') # NOTE!
+ {My name} is {{name}}
+
+
+
+در نمونه کد پایین یک تابع را مستقیم در داخل متن موجود فراخوانی میکنیم::
>>> def to_lowercase(input):
... return input.lower()
@@ -1459,7 +1501,9 @@ f-string
-.. rubric:: برخی از متدهای کاربردی یک شی رشته
+
+برخی از متدهای کاربردی یک شی رشته
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ``()capitalize`` [`اسناد پایتون `__] - یک کپی از رشته که نخستین حرف آن به صورت بزرگ (Capital) نوشته شده است را برمیگرداند::
@@ -1672,7 +1716,10 @@ f-string
-.. rubric:: چگونگی ارايه نوع رشته از موارد اختلاف اساسی در نسخههای 2x و 3x پایتون است.
+انواع رشته
+~~~~~~~~~~~~
+
+چگونگی ارايه نوع رشته از موارد اختلاف اساسی در نسخههای 2x و 3x پایتون است.
در **نسخههای 2x** یک نوع جامع ``str`` که محدود به کدگذاری ASCII است؛ هر دو قالب رشتههای معمولی و دادههای باینری (متنهای کدگذاری شده، فایلهای مدیا و پیامهای شبکه) را در بر میگیرد - رشته باینری با یک حرف b در آغاز آن مشخص میگردد. در این سری از نسخهها نوع دیگری نیز با نام ``unicode`` وجود دارد که رشتههای خارج از محدوده کدگذاری ASCII را در بر میگیرد؛ برای ایجاد این نوع اشیا میبایست رشته مورد نظر با یک حرف ``u`` آغاز گردد::
From 4715e91d133fa5130bebdc9ef64ec145697489a1 Mon Sep 17 00:00:00 2001
From: Saeid
Date: Sun, 20 Oct 2019 10:25:08 +0330
Subject: [PATCH 022/294] add re ref to l07
---
lessons/l13.rst | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index 9c7c081..09d5e8a 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -201,7 +201,7 @@ Decorator
**functools.wraps@**
~~~~~~~~~~~~~~~~~~~~~
-در پایتون عنوانی مطرح است به نام **Higher-order functions** (توابع مرتبه بالاتر) و به توابعی گفته میشود که اعمالی را روی توابع دیگر انجام میدهند یا یک تابع جدید را به عنوان خروجی برمیگرداند. بر همین اساس یک ماژول به نام ``functools`` نیز در کتابخانه استاندارد پایتون قرار گرفته است که یک سری توابع کمکی و کاربردی برای این دست توابع ارائه میدهد [`مستندات پایتون `__]. یکی از توابع داخل این ماژول ``wraps`` [`مستندات پایتون `__] میباشد.
+در پایتون عنوانی مطرح است به نام **Higher-order functions** (توابع مرتبه بالاتر) و به توابعی گفته میشود که اعمالی را روی توابع دیگر انجام میدهند یا یک تابع جدید را به عنوان خروجی برمیگرداند. بر همین اساس یک ماژول به نام ``functools`` نیز در کتابخانه استاندارد پایتون قرار گرفته است که یک سری توابع کمکی و کاربردی برای این دست توابع ارائه میدهد [`اسناد پایتون `__]. یکی از توابع داخل این ماژول ``wraps`` [`اسناد پایتون `__] میباشد.
**اما چرا معرفی این تابع در این بخش مهم است؟** وقتی ما از یک Decorator استفاده میکنیم، اتفاقی که میافتد این است که یک تابع جدید جایگزین تابع اصلی ما میشود. به نمونه کدهای پایین توجه نمایید::
@@ -311,7 +311,9 @@ Decorator
>>> waste_some_time(999)
Finished 'waste_some_time' in 2.6838 secs
-در این مثال از تابع ``perf_counter`` برای محاسبه فواصل زمانی (time intervals) [`مستندات پایتون `__] استفاده شده که تنها از نسخه 3.3 به بعد در دسترس میباشد [`اطلاعات تکمیلی `__].
+در این مثال از تابع ``perf_counter`` [`اسناد پایتون `__] برای محاسبه فواصل زمانی (time intervals) استفاده شده که تنها از نسخه 3.3 به بعد در دسترس میباشد [`اطلاعات تکمیلی `__].
+
+چنانچه درک کد ``print(f"Finished {func.__name__!r} in {run_time:.4f} secs")`` برایتان مبهم است به درس هفتم بخش **f-string** مراجعه نمایید [`درس هفتم f-string `__].
From c2b057c1e06a87658bafef95b3de4cb3086561f5 Mon Sep 17 00:00:00 2001
From: Saeid
Date: Sun, 20 Oct 2019 10:47:09 +0330
Subject: [PATCH 023/294] some edit on l07
---
lessons/l07.rst | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/lessons/l07.rst b/lessons/l07.rst
index 3f3b3e3..b170483 100644
--- a/lessons/l07.rst
+++ b/lessons/l07.rst
@@ -1493,8 +1493,31 @@ f-string
>>>
+همچنین میتوانیم هر یک از اشیا مورد استفاده در درون متن را با شیوه خاص آن شی، با قرار دادن یک ``:`` به صورت جداگانه قالببندی نماییم::
+ >>> a_float_number = 5.236501
+ >>> print(f'{a_float_number:.4f}')
+ 5.2365
+ >>> print(f'{a_float_number:.2f}')
+ 5.24
+ >>>
+
+::
+
+ >>> a_int_number = 16
+ >>> print(f'{a_int_number:05d}')
+ 00016
+ >>>
+
+::
+
+ >>> import datetime
+ >>> now = datetime.datetime.now()
+ >>> print(f'{now:%Y-%m-%d %H:%M}')
+ 2019-10-20 10:37
+
+در دروس آینده در مورد ماژول ``datetime`` صحبت خواهیم کرد. [`اسناد پایتون `__]
From d411c598714e79aef1cfd319920008a3a25a08e4 Mon Sep 17 00:00:00 2001
From: Saeid
Date: Sun, 20 Oct 2019 10:54:30 +0330
Subject: [PATCH 024/294] add l13 report
---
log.rst | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/log.rst b/log.rst
index ca07fc3..d9569dd 100644
--- a/log.rst
+++ b/log.rst
@@ -9,6 +9,20 @@
گزارش توسعه
=============
+
+.. raw:: html
+
+ 00112 - یکشنبه ۲۸ مهر ۱۳۹۸
+
+* درس سیزدهم با عنوان «تابع - بخش دوم» به فهرست کتاب افزوده شد.
+* بخش **f-string** به درس هفتم اضافه گردید.
+* کمی توضیح در مورد دستور ``return`` به درس دوازدهم اضافه گردید.
+* گزارش هدایای پرداخت شده بروز گردید.
+* یک خط فرمان پایتون به صفحه نخست اضافه گردید. *برگرفته از وبسایت پایتون*
+
+----
+
+
.. raw:: html
00111 - چهارشنبه ۵ تیر ۱۳۹۸
From 350ac8b1b75897a8c793f3f5e1eca8314b5bdf5c Mon Sep 17 00:00:00 2001
From: Saeid
Date: Sun, 20 Oct 2019 15:18:39 +0330
Subject: [PATCH 025/294] change google analytics code
---
_templates/sphinx_minoo_theme/theme.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_templates/sphinx_minoo_theme/theme.conf b/_templates/sphinx_minoo_theme/theme.conf
index 7e2db3b..76517ed 100644
--- a/_templates/sphinx_minoo_theme/theme.conf
+++ b/_templates/sphinx_minoo_theme/theme.conf
@@ -15,7 +15,7 @@ language = fa
body_max_width = 800px
#
# Set up the web tracking code (Google Analytics).
-analytics_id = UA-61670451-1
+analytics_id = UA-107863650-1
#
# Your links:
# Whichever you don't want, left empty!
From 0f7ef848729c8033cb6bd9e953505b5800c970d0 Mon Sep 17 00:00:00 2001
From: Saeid
Date: Sun, 20 Oct 2019 15:59:01 +0330
Subject: [PATCH 026/294] modify footer
---
_templates/sphinx_minoo_theme/includes/bottom.html | 2 +-
conf.py | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/_templates/sphinx_minoo_theme/includes/bottom.html b/_templates/sphinx_minoo_theme/includes/bottom.html
index 51703cd..2f7b6e9 100644
--- a/_templates/sphinx_minoo_theme/includes/bottom.html
+++ b/_templates/sphinx_minoo_theme/includes/bottom.html
@@ -39,7 +39,7 @@
{%- if last_updated %}
- {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
+ .آخرین بروز رسانی در {{ last_updated }}
{%- endif %}
{%- if show_sphinx %}
diff --git a/conf.py b/conf.py
index ce71d64..8f890dd 100644
--- a/conf.py
+++ b/conf.py
@@ -47,8 +47,8 @@
# General information about the project.
project = u'کتاب آزاد آموزش پایتون'
-copyright = u'2015, Saeid Darvishi'
-author = u'Saeid Darvishi'
+copyright = u'2015, Saeid Darvish'
+author = u'Saeid Darvish'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -223,7 +223,7 @@
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'PythonPersianTutorial.tex', u'PythonPersianTutorial Documentation',
- u'Saeid Darvishi', 'manual'),
+ u'Saeid Darvish', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
From 7bb3f95646f712f4d68e195a18954b954fa99b93 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Sun, 20 Oct 2019 23:42:24 +0330
Subject: [PATCH 027/294] add link to coderz.ir (11,12,13)
---
lessons/l11.rst | 2 +-
lessons/l12.rst | 2 ++
lessons/l13.rst | 4 +++-
3 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/lessons/l11.rst b/lessons/l11.rst
index c000674..4190665 100644
--- a/lessons/l11.rst
+++ b/lessons/l11.rst
@@ -830,6 +830,6 @@ os.path
:emoji-size:`😊` امیدوارم مفید بوده باشه
-`لطفا دیدگاه و سوالهای مرتبط با این درس خود را در کدرز مطرح نمایید. `_
+`لطفا دیدگاه و سوالهای مرتبط با این درس خود را در کدرز مطرح نمایید. `_
diff --git a/lessons/l12.rst b/lessons/l12.rst
index c9247ab..a1b8892 100644
--- a/lessons/l12.rst
+++ b/lessons/l12.rst
@@ -821,5 +821,7 @@
:emoji-size:`😊` امیدوارم مفید بوده باشه
+`لطفا دیدگاه و سوالهای مرتبط با این درس خود را در کدرز مطرح نمایید. `_
+
diff --git a/lessons/l13.rst b/lessons/l13.rst
index 09d5e8a..dc1dfca 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -2,7 +2,7 @@
.. meta::
:description: کتاب آنلاین و آزاد آموزش زبان برنامهنویسی پایتون به فارسی - درس سیزدهم تابع
- :keywords: آموزش, آموزش پایتون, آموزش برنامه نویسی, پایتون, انواع شی, انواع داده, پایتون
+ :keywords: آموزش, آموزش پایتون, آموزش برنامه نویسی, پایتون, تابع, Decorator, پایتون, lambda, Generator, Coroutine
درس ۱۳: تابع - بخش دوم
@@ -791,5 +791,7 @@ lambda و توابع ناشناس
:emoji-size:`😊` امیدوارم مفید بوده باشه
+`لطفا دیدگاه و سوالهای مرتبط با این درس خود را در کدرز مطرح نمایید. `_
+
From 1b967cdd4fdf9e6806299008390da72aacf0a36f Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Mon, 21 Oct 2019 00:29:41 +0330
Subject: [PATCH 028/294] fix l13 text width
---
lessons/l13.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lessons/l13.rst b/lessons/l13.rst
index dc1dfca..68c502e 100644
--- a/lessons/l13.rst
+++ b/lessons/l13.rst
@@ -313,7 +313,7 @@ Decorator
در این مثال از تابع ``perf_counter`` [`اسناد پایتون `__] برای محاسبه فواصل زمانی (time intervals) استفاده شده که تنها از نسخه 3.3 به بعد در دسترس میباشد [`اطلاعات تکمیلی `__].
-چنانچه درک کد ``print(f"Finished {func.__name__!r} in {run_time:.4f} secs")`` برایتان مبهم است به درس هفتم بخش **f-string** مراجعه نمایید [`درس هفتم f-string `__].
+چنانچه درک کد دستور ``print`` در تابع ``wrapper_timer`` برایتان مبهم است به درس هفتم بخش **f-string** مراجعه نمایید [`درس هفتم f-string `__].
From c75973ca97802e4e952676540c3b0f6a37901348 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Wed, 23 Oct 2019 21:40:59 +0330
Subject: [PATCH 029/294] create l14
---
index.rst | 1 +
lessons/l14.rst | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+)
create mode 100644 lessons/l14.rst
diff --git a/index.rst b/index.rst
index c62d637..0ad180c 100644
--- a/index.rst
+++ b/index.rst
@@ -28,6 +28,7 @@
lessons/l11
lessons/l12
lessons/l13
+ lessons/l14
log
donate
diff --git a/lessons/l14.rst b/lessons/l14.rst
new file mode 100644
index 0000000..93d5eae
--- /dev/null
+++ b/lessons/l14.rst
@@ -0,0 +1,49 @@
+.. role:: emoji-size
+
+.. meta::
+ :description: کتاب آنلاین و آزاد آموزش زبان برنامهنویسی پایتون به فارسی - درس چهاردهم تابع
+ :keywords: آموزش, آموزش پایتون, آموزش برنامه نویسی, پایتون, تابع, Decorator, پایتون, lambda, Generator, Coroutine
+
+
+درس ۱۴: تابع - بخش سوم
+========================
+
+این درس بخش پایانی از بررسی تابع در پایتون میباشد و موضوعات باقیمانده از مبحث تابع پایتون در این درس بیان میشود.
+
+
+
+
+
+
+:emoji-size:`✔` سطح: متوسط
+
+----
+
+
+.. contents:: سرفصلها
+ :depth: 2
+
+----
+
+
+
+
+تابع بازگشتی
+------------
+
+
+
+
+
+
+
+|
+
+----
+
+:emoji-size:`😊` امیدوارم مفید بوده باشه
+
+`لطفا دیدگاه و سوالهای مرتبط با این درس خود را در کدرز مطرح نمایید. `_
+
+
+
From 184938f1bf7d5c7d7bf0e41e4b6975747e0ccba2 Mon Sep 17 00:00:00 2001
From: Saeid Darvish
Date: Wed, 23 Oct 2019 22:57:20 +0330
Subject: [PATCH 030/294] start Recursive function
---
lessons/l14.rst | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/lessons/l14.rst b/lessons/l14.rst
index 93d5eae..270b471 100644
--- a/lessons/l14.rst
+++ b/lessons/l14.rst
@@ -31,6 +31,36 @@
تابع بازگشتی
------------
+از درس نهم با دستورات کنترلی ``for`` و ``while`` آشنا شدهایم، این دستورات تنها ابزار ما برای تکرار قسمتی از کد بودند. اکنون با پیادهسازی شیوهای جدید در تکرار آشنا میشویم.
+
+به بیانی ساده، **تابع بازگشتی** (Recursive function) به تابعی گفته میشود که خود را از داخل بدنه خود فراخوانی میکند. پیادهسازی تابع به صورت بازگشتی شیوهای است که از آن برای حل برخی مسائل بهره گرفته میشود و باید بدانیم که توابع بازگشتی، یک سینتکس یا دستور خاص در زبان پایتون نیست بلکه یک شیوه حل مسئله میباشد که با استفاده از تابع در زبان برنامهنویسی پایتون (همچون بسیاری از زبانهای دیگر) قابل پیادهسازی است.
+
+برای مثال در نمونه کد پایین مقدار فاکتوریل (`Factorial `_) عدد پنج را به شیوه بازگشتی محاسبه میکنیم::
+
+
+ >>> def factorial(n):
+ ... if n <= 1:
+ ... return 1 # 0! == 1 and 1! == 1
+ ... else:
+ ... return n * factorial(n - 1)
+ ...
+ >>>
+ >>> factorial(5)
+ 120
+ >>>
+
+عموما میتوان مسئلههایی که از **توالی** انجام یک **کار یکسان** قابل حل هستند را به صورت بازگشتی پیادهسازی کرد. مراحل اجرای نمونه کد بالا به صورت زیر است::
+
+ factorial(5)
+ |--> 5 * factorial(4)
+ |--> 4 * factorial(3)
+ |--> 3 * factorial(2)
+ |--> 2 * factorial(1)
+ |--> 1
+
+ 5 * (4 * (3 * (2 * 1)))
+
+**پیادهسازی شیوه بازگشتی شاید به نظر هیجانانگیز باشد اما نباید فراموش کرد که میزان حافظه (Memory) زیادی مصرف میکند، اجرای آن زمانبر خواهد بود، درک جریان اجرای آن اغلب سخت است و اشکالزدایی (debug) آن ساده نخواهد بود!**
From 8c6b658f07ef47004a60e95412e4508cf74ac96a Mon Sep 17 00:00:00 2001
From: Saeid
Date: Thu, 24 Oct 2019 15:10:03 +0330
Subject: [PATCH 031/294] *
---
_static/l14-factorial-relation.png | Bin 0 -> 15826 bytes
lessons/l14.rst | 21 ++++++++++++++++++++-
2 files changed, 20 insertions(+), 1 deletion(-)
create mode 100644 _static/l14-factorial-relation.png
diff --git a/_static/l14-factorial-relation.png b/_static/l14-factorial-relation.png
new file mode 100644
index 0000000000000000000000000000000000000000..a1c127e12ba90abab796f7016d020e3568dea367
GIT binary patch
literal 15826
zcmb8WbyQVb*e|>Z=`InF5*4JoOBw}46e*=kKoIHfkX8X{P(q{|q)Qs4yQKuAL-IcR
zy!RX9y?=h5;~8xB+I!74=M%qpPUsU=1$-PT90US^ucRpZ6oEjwgr8qyVZeVYCqg<9
z2)rt{XIc(V4V~%j>}|~~txf42Ts2M6!AFF8ELX{X%06@@;z_7&+*yVhs7@16bgeKpr{w7K`|&CjNJO@O#>`N(!xMq2D8N6&IhKJu3K6AY-{|fPCHBR)`FDakr
z%Ipzd)K4q|6RmP9DyKHTl@-S6T2@qyC2fxUsfmB(zF8k7aZcs>NnL^3Gn~64k%yN@
zv(>t6fO}0ZEUB=xdTi;U9fiD4r~LJBp-fI8zNgcqW7X`*#5+#Xo*;B|t1+92a>pTG
z<(y=pSH!k>s|UpV_(?vAkW{pix{oh{=-O;m*Gk1jCULRli9|w
zq>BJOyY(x&&Ktph1%F??pCGoSd65)FDsRkL(uvc=q$u6PjzpE+b*x7?@7i0Tz
zmr2*u63gG|$1IL1#Co>xEyZV)t+zQs+2vyE$G8$L{o)x-U5|cjO^G?0$I5EkY%m{%
z%N+#8a17DZX8nkG?UY#5y;1u+kWH|7LMcd@E{0I}$u}#`N>Mp8*dy281$9oGsME5v
zJ%ytDto&)_lG20>k#X$4NR^n9$$Y1psfBJKb?uFx*{q7M>m0R2+rKbUJEm&9NZuB}
zAtTpVzi;>RJ8z$k-Z#RT$+Fuiq77&2{oRSfHoA_0DtCky#Zfezum3iC%>j1O}-^z
zEqQM7IXeX{iFGSM)O0i;k%N_nbEf))iz?izyf{C1iXb34{Rz>fal^uqCjseA@5Ta=hkH2xxJ|?lI~fTa
zLMRWawFw>tP1z;8Ju&3_W-VA>^O8LK>0{I;4z!es?l-IWbK8BTH~+P;QbeMLtLuze
z2=t@I))hdjCGoF%JLgb=5Fqwd_r%IztiD{1=Y*&qhCx
z$0Yr{?R9E0kK?90Ds;oGtVWZk-VcxT68+waE2~v*A#rN6>ukA(yccOt$1OVok4@r0
zr_D!A-IT#<8JS(5YA)8hox0a*x+#lp
zk}RUiD*ra4<0Myh#+J4(0G(+HIN8Jj^g@_vpl_;YaWzeoHGX4X>BxbHNo
z;@rG-qr~xTEVIpBb*ktr%v!-g0j7-4c;_ey)N6LXa#?)er#~t}JU1cp>w0lnzlQn4
zce{M)x$R;snN!bZQqItyOhS8cRC!5b+Q4FiR(6#WC#?R08Cd4w>I
zPrZf>9fi5=4JrFWvF0zoUP^fk{bX4D5`a#bcJEeZWfjRVar-S#VbNPGA~<6+H=jy(
zhO3aF2OG#cz46b$Hnclw`FdhF)!uJ8rL4Ijox~k-mxuT}SMi;9AAPTG;5X&2-!~&;
z@ZH&f0
z+N%zfBvuD69-@0K&{j|&CK^<0R0a5MN_Gt8VDsIKy20~mCbJLIUo?j?(}5uJ)~|g3
zvUFKmx6eGC*t?jxb+kIzoR7(g2ks4171l2l7I(d?_?6M+O3bM;{qpFS@-zRDYBtf^
z(Woi|?Kb{7{v5
z=V-4hcmoZ?*pzXd%ksve?q^wp;`Nn3@&nYU%)QUhc;w4pVcxe@u<6-)Ll-GiPcU8B
zv_?KdeVM0CnkE_QT#@wExP~$64!kadb>Hu`vVS5*
zI4isfS(c|9PGlkQ#4P61QN=x)N5isj$mBfn5;R`g3qD|7%=%Hyjq$-7VKGF9jZQ_(
zLL&c*mV_{Itx(yAC|+NW!n8=b{yOsXrhMRA{}SKCR@aA12D{24CB*@e{FU+lI;
zv7etyeD9)iY7E5-HRq}wyBl1R$^Fi4dYC)NFm>kZ&J89-oCIFy9Gjx%u0IDXT-@Z0
zl^NgYeLhnq8$UgL$l@I<1`K`$DiS~iq|&PXY{*H
z^|5)fvH#})_U7A^46(#mvX}us*hN47z@=D>rqi&O?lX;(5_py=Wqjw8UXifLMA$C&
z=e|aa-CqIB!ltp?m}|{
zX!m=4)0naPsv_Y0dUnP(E6*22)zV5VR66ltt-)_@^v*lnR?RFo=mes;%+`cTx9VFE
zo)-7*vX`>a*|)3NQoa!?rsivJyd}(8Jtd5zxjdKu)A4hVfp1|5Ez@2;V;a+jhb=mh
zH>uS#i8$bVpOeBvPl#PcLWeJgz=McBY3tQ7cPYa=r+q9R(W1QGO?K<84>Vg!qN`QQ
z!-P);FJm{9FGNWl{Mhs?%;hE&X#Bf|K2kpm*!PTjaumvMA?~-yLgYv5@SzObo#+St
zfKxaxpWwZB9)`Gmtyyk#h5Z3a*Y9Kh`S=8q$XO2^?8tk4KNm;WFXwZ8yrr(z`7-F)
zrvTE`>gd)%;&Jyc)SC`FgOOd9WH
zx}GuEBpuM&%f6YKAw4rycD2DjjDIqPca701u4j~9^UMf1O@O70%o8OU8Tuzr)#Q~P
z%K>po_KXo%Y?Y#E*Vo8;`hdWRc_}(WM4S0}n|j`p0Gtd>i_zxaL!1^vA2O?ja0+i=
zN>bzzaP#pm1YpD5i2}b$?;%VEA4g-
zE7P_x$N1}
zG4M;5F|YmSXA|4I0+Ps-Q7<_wFS#+$oqU~!D;uM1YCTa;(|lR$H;XEK64Zv0Ub4HP
z_xMOm#}cxZm~Sbp?VVn3Kr|NALR
zjR;+u2%W|AzgLPIq{vs&%4x`}u%4d%_bPhmKJt~{Ckf*<-e3@Lw3TjD7Nm+S$MsDsHGPre{C_O(vIqAK}KDD)?s>wow-*=v;
z(Z)NmUPMO|B@4av`=5*adR7=8JisBnuZr%YS#a7_SCl0yC&$3Vgs!Tpx_fkV*B2h5
zPUha@&j{M6VEE|Pd}HJ2-2H@;3ZjfBA--ss51GmQ2G&|Jnw=elz8@KL+>?=!QDDzX
z$KuI;2Uhzqg9x#(x|&^b(BO82V`yl&ySwXCUoRd>D~?m5^%(Vj2*sDoO!URY#c%of
z&(3Lb)Y5`rW9Hm<#Ctz;qlHnhe>tg4_!Jw23sK%ZDS`ZU*dD~f@82U^
z@3`^&%?DBqhqF~qPnV+>x3?pD;yFJ?V}A*ZQDpkeV~VrdpAzPJuqyq0{DH3&LSJ9M
zH-Q&3G&B_9^XU`Wr}+4|`g(v?q?`xdJnp(ec)#%l>a{F>!J3
zH#0&tJL82fr&m|*5n&M#6Z;x>L^3ckqM~8oJ<0WY`SLbwOSnHKA>*ApXo!WSCDc22
z?p&O07E#rz!B2sgkZ=!evN)%|jkxWeooN*tpkT++&&hS<6-C)hSLQyufA{WUX+Si`;-MDc>$YGs`k&$sCp(ZpG+r!gy
zu+iJQqJLv~*`KrVf<%wwrih4$tz)UYa@rGY8|8ULqJUM1W?4;5ioC`@g!S
zqX>EVW~SQr_ivMY{YKi`qD~h*B8)Lu2?+@ZpA4B`fu7KUl1YolkMStjw9@S`Uh3$)
zpZC7Lt(GPc2zj=(z0J>YGsrMHE-uLP{Fp&Pf))Y*fuN?QX47w=Nli`V5)c?mT(f@j
zrvHJbC56P(vw)#ax4)$587Y}rS%&Aw+gOBzn25vmK{QCJ>mD~@VPX4Kn-VR&7{!3(
zWE$9V8GZfw!n*2eN@@Y?rpYpM28u8SBCOq6=lQN!Vb3!@r|qfsGt%%|ycpcv+*H&q
z5X=8J@#(=jJ%znJ4q#spc-0|hz
zTEETGzpCskI0PLm)6qLv+Zp-!c*tDW*1q*-t}Zl!T9A>0gW%r1dz9QpvR{w>&eh{8
zC@4I8_N>!0H9o#0v7saUmOq0`&^HIk(a}*XEG#J_BSxp4xd`Opz+Z7h)8HU6B04rU
z@Ohr5G-C|Cm>3N#)p}wFinjpkpEOu9JdfS(g0uiCb8xF~R1~3R(JOpbR#u1gUl}SD
zDE|e>cEH)0TW_*3DROa;N>=aJ>}%Eszbbq^%FoZ=T_3!|h3Ai4EgKsil&ihHJ!|WT
zH?u!-t}h&mxWw>gwtic6JB}g8iXR
zRyJg1WlbsnJ3HDuy*l5S^bvYl>l7Fqj0pu1la)2EYDr~&jse+<2mL6isEh``$ZfH`
z{Bac5v+_kFM>S%Mmy62>?#D!eO)Kezmu@KBG&Dpq`@>P=+{?ky5!qFacMcC75KRls
z{uwzrn9w*~+}({K1g&pv%();aCB5pV#wo(u^KB6b$X|nt(>*R;-aCQUap?h~I;b||
za83$Tlo*J6s>$D;-42y)IYSAj5iZrnxpwUC>DgOq#~mvzHf+T>{4@GUbrG$}w(;_(
z4w`%&eS>+LMC+_ZVd1B3C^ddr~6Rh{)b$)<(Nnoqa?2o2rXS**7`NQ#0WL=O`iuR
zOt+r^f-o9L6}M$}^p$E#{9RB`khIcva`Eq79kf-%ue=wWu+?NQie9zD(Q|vAIn30%
z-<+8L|5h8ClR3y{d14kU;Rs##_A>*Qdz+ngWIG>bR=W@-Wq8
z+1tgGe&;?=Xa*jLp3uG+l{zizkagN>%BcdsqLFSWca~@l%CORD*
zU0}aM)tgz=U&RG)pu|wstiC5_#1TsMuvrMjUfanZ6`z%
zsI31ZRnq=YZd4N12{#r`_kbG~^APW=Y-w1JN0jwoVE%8=F|kdks+#Az$!!v~VB$ui7}iV79z3UR_JIm7ku)(EKA
zyvFjiaeA2U-!JQMa&kiW0IYxubF{~y0E!}E*6yxdTU*=0a+IX}t5>uHw?zWpF8}oH
zSYEukJpWcu5C}LSzo3Aait0V2`o%%owd~GZebT3-@11{A$JtXe5BWPc7fo~--;oXq
znVOnH&WmB-Qw12d1|jhsGdsH}xIifSiKxZuvo}WMpOz36Ljx9UUFrM0>J1P6*AR
zBU9;P)7n8Z*W<58g)eI{ql{k9XLl<=r-;emZKiE=;Q3caHcX)sl88Lh}f
zrTzn1&miOgh7i-y5yBrtQ`g7)+;5j;dy@nSA-UvCP46NW>QClc`%^^UUSE0QQF2Lr
z)g)wrdP()qrgR{zWmn+K;b^^>fFT1E_{0qoa!eK(O%fO&cF6E4RSUiyIr*o}QkR)YN(W3rqGj
zkV$VGmFap#nOIrFP@1l4Aq-@ggL+m-m$e`)OS8JVwfo9wj-xv9+}oo*f>MgagU0tkhhwf?`;@#>K<)n%_n}*s{BF
zq(#j8iY6{DZp(s)mzUHZ1OJPqub+0q7IWIbnnt#`-!I13R#tlulPyr%D=RCN3vS({
zpg_L(_wOIo4z(4$yIIs|1Px^!lJ_e&8V(MQ-QO8u=rT>+-G5R#IRpi7N=r*)VPhLs
zooMUo-r?p}-@Y4llk-(N&=)s1w_k&UhV02jx`Mtzv*>?xD1b#x+#LptV=;5w+_n=H2^H8wJ8K^UBRc;z*k(?)e1&*r@-dP9Da
z88_5uzw$o0)a&dpcjlzMy}h?Pmi3m5j7(*(=ml4={&_Schc@!hlqsjaL-j>mU0n&m
z@jrO*U}E6t@Ni<;YP`^JV<^jdT~RJI{3#wD-meO)7rE^y0BP7?kGlNZ&yxRg1w`_J
zgNG$HDk`eheIg*P*rfNO3qH|L3GwsuSG%8Z;NjyhuB^zR#$*6~)v9`vqB)ZXkU_w9
zE}UJr638keJv{
zTok(=m|a{P3~WWc$UMY^a*`xy`vp*-TS}`CGfdbQal)PqmKoZ862=8-q69cI+
z94~(O@ZoyI{SYUqw{N+<&bI}HL`4NzW7+rq#;DE!nt!{{gaZ5@I$xz%);x4!>)9XV
zg@uJgp|aK?V<+?8bn^1@Le76_DsAT@i;KA+JL?TmPIp@g=j*B)BsSTaSL}74ZH$kO
zGO)7Z64FUnAJ|CK!&rDpP>**HtPA<)nETiHr4gcTb4*
zsoaQ*HjDV4mnRcUa9d|9`1sE#F6>BR8a6gIox_#+Qd8XHoq0lDUf!+gs-2Wb
z9Be-e*FZ_&nOk%9)R3mtE_;l}e`mw$-A`JkrV`Odg2)<^lBl6Spdl3x1qI{z22Weh
z`*AvhcK;vbV|X|O=&{6cQ?rKsHlWF^9}Oc^=~x?@A#t>Qz`I*!XX{4=!@qrFh7?Cd
zz;l6iAa9E+U2gc{<40m>ahaJ+pFe+I*jw&6J)X8jVnz~G>ejwKeE2qyMdThnL?t05
zoj=P|E#RsfLdOGEDQ{pvzdDc>r6zg#tgsh}%>L%m@R~jTdj2%4%pIqB+K11X5BRo}
z6vEotdLok&UAkPnKUEwzouR%uBZHx(rG7TqJ01^?Kc+9T`;*HGAFnm62cN#$%uEH=eHui_Cj!sCUpP~dj@>$Yb
zLOy~j@KwE=A=K~n*;+yDZ2Siop``bb!cE6=y+)38Y^)bF9IHxBR@T;3arZgJDlKho
zz?E=ByP%NpyGcOm0*=Ilb+KO=Lu*ji*Pr*u*w}206+>ZQV1OP3^*bmnjjp$^&$5SB
zx|{)!HaFm_a5~AWWnN%`ne2s@UPm$$|1d;Qa-eFFMewH^mlZbK6j
zbcwX0J!@T%+hlvV>=vX1#+0qF+Vl1u_yq;y9hZ_op`ga0i`E~gs;aWJ*UbO=^+0oJ
z`^B?o^q`hiNbv>Vz@@0Gz%+UDhConIFd!%h_QvS?>JsQwx?m_h)|XgP5|Wk&9xq;u
zYZANbn`Ut)-TYB<_&y>wx2VYcJOf61Xr?Rk+!1?bC%CF)RuZ1RG+fTWLg+D=^LGb0TB_$+e
zz}t-%`?w;`f7xz6Ep2F^g>o1Y71iN`f<{C^F=q6>5m4Ji&AS{;0U8hqA&HQ35LB-R
z58hYq6GMO*LBm^ddQ}l8p_|3-4h7ZwVh__N$npL7?Ngs1DbiB)9UdN@-AVH_Ly#~|
z7yJo-cLxOr8v_zmR8ndNmR)f#b-(uMMQH@=gP%n`)4hA89Yf3&Iyr}BWo0X7d+*Iw
zpa^UwHjYdZT1>2-{4iaBPuY8i$udT`j8{2=p7J@QQ67jV2w8CY_Mu-AAIe>8`ni~c
z-t~KR^-FcN)*bA2tUmgeJ($0~Cl|$Pp5e7FKsQ170I}txdff5r7ZHdGH+~hPBUK$x
zAptftsyjhjrxbic1J5A|Rn*nEFO5F2wZdwg3#x~fj!sKg7dF&Lm%SyqkB$#mSr?a=
zzs5xOO+D7u*8VteZeqe5J}AwsprnM|(%P!7t(|);tePf)@9gYccQWVxncEnHf?Wq4
z)Wa5=W~U;yQi{p3g{J#*8#f#PT=k}i-UNx1QpADT?dVTdv0fCdxZTx-D;7Gc$KjxY
zHHL(o!^Y5!cuswJU@qYi5iHC%GPq$CB{tInG(vVheWWolF}@O>XX&6)MU3SY6tn}v
zeY-iv4(R4_ib%z57YFQ^b
zXj!WQN$ZMti)y6(F<2_0Ve7;M
zCG6r)kPSd_Rnh+UEO~Uk<{jpJwbZuJycaR?@tCwxE4N7}(c@&HlEIj(QqvwHYHD0S1?^!st8iWGf!P8L2XNZH(i8u@u+eIq
zL(JopNYrUd3UZL=CW%^nNKJ$K>EOIYc=gjP^x|SBQdX*6vy?XVElK(ZCSzn@D
z%X7b_B_pJOE+Rq|&++oLvl;$F+=)6@UNj$oR>HzDQe;nbb$g(X^B_LMlk+^xc(U;W
zI3OP4XG@EpD}-uN{BuuFaZ(zZUf^CO+uehMF$sdUwC95HJ*M5=-B^6>2}PJSr(GJMWpH?B?+}wR1Y(ZuZBVoS_ad`@ae-
zqN%M79pH-2KT*{bksA
zK6Zf;pxpDOBl5N_di)1QiZJ4vH-q5=(r@U8;x;Bq?)(SPfOy!KJ$;z^{rdyG8v7f-
z%3tX0g~~EkdVxi(7&&+YGw(B1rlmTY@ZF
z)wKp+*mpenzOuf7x3fYyj4;fhR8
zH<5xfUQ~xMq{ZZcN}5DUjl;$V`7=sKY#ba$1&J@)$gBvb6{i9$Yc$?q8jk~L6NwyG
zR_@08X{o8H-8t8cq7n8Zz9Vk{=(O7Nyi(pv13Vj4G&FASD-VH-cThU&>g%~7fWSnl
z8?*v2Sz@-X{#8B$f;QsSeNfHe05g)e+>W=py!16SF~CCtDzFS_mMT6);MZ3L!ilLV
zR12)y%l(x{ZW|_MC$-KyLH_<|(84AMU};k(;u2|u-rn9oQ_9jn^~8l1NGV`V2@+$=
zs*HLpP`{SuW)x7kRE{yg8n3TJ1>VeHk&=>vM}s|_qt?+D
zO8WM9C$T;H-2;g|5!k2)u|>JL&Exvs5lu}}NCoHmv_o=YCzHSydh71~{zLF2pqEAf
z>nSw_T_v-$47Zg_$m^myx#f|XngXcXOG`^nbabYyg~8P`2BS!;(M$aAY;A|v6@+7E
zW~LMy#a9qD!R7R8IVR_D!t+kw5A%o-PkK*Q9C?HDkU$=I;0;{ORe1H~+i7rQ_-$Ig`wa48OvNI@~c7P5E`aZ!-qc~TS2FS
z_CfIAW+4y>GXt_yKztXM7Q+A&`e~{PX8EbS%Tu-9;hqD>0Dhe}NrU
z*$@~g_tDUMngj^<`cwt$xuB`Pbvi&(Ui1DoP*w~qExSZi?Q3T46+F_^)O0yqCoU~5
z<#PV3S2;Ud^DfwCer+J_g{vn7wtk^xv`#+c+sYXl=ugOCgI;PM=?@CagA>e%!6JQ0
zB+o4=DZwHj2#Scn|NDeSei4Bn{BIUuwlqY
zZ=|OHn`+%LPBUBuG9pkKL*Q7Thxex;@@E4JpZkt|H|4hfGgT4=`60l)BcrIa+=1Oa6-c_|k?h)3*SmTgM5*K6@OEz5p}M
z>yF|3XEkqyXu!F6nq`GY#fJqA8Ve5(X_kRBiL_pk9s)oE8DQ9Zr+da=PTvM87g&)+
zoU;|=@TrG{PtZ$(i1xAgtn6(0H$AEvW}4cYK745Lpr$lj9_vz4QW^l4uwMZTt2GHa
z7xSg){=vap_?;Q%OUTh5Kh2E3GqSqBeEAamy1FuV%LqlZR)hr~)8Qtd+Oby8-<>ha
z6}F}IN%nrgC`
zD~U$-<7TJ_hNh;YOS*p(!}8@cSdVW?EG;eVt)`_~sgC}~
zR2k{IVFSV^00l1FWeEq^Gy#-|Z_l1tB9#Oi5k
z_SmT8^KCs?{S1^}78Vx!1_WbFh+}?fMa6R^C!~1-T6z-v&jG{3D{+)__ex8lwKHX1
zQw=%yAzR;yHbCF-a6Ci=r%W#JC@9far^|#uy}Drp4c*$C%Vl?=>H~EHKn!FBgXs((
zAe{_g6~KIg>2(^v6$K1Fya(~PYRa5_`b8stLd=k@KPX6*3~*52`Q6w+;1-SU>{JA>
zT0ck+s^MmV6^H;;s(CozM2AE~$N_EHybTr18-$Q_{YEdBi&O4Do0~}mWPm~}eJG!+
zn@|L_j@2zh%97TdffRS{c0zow?B
ze*XNaJo?dWS)*Mfy<0qYhz^XX#^)W+AP6XL-Ri1O8_EK$N2kE$FCd75KVFI(RtZB<
zk&$MxVIrM{g6^)aEO=|T=;#J$^GHAb0LdG97El~RE-pMEeLP8krod;B8N;Gp)K!p
z`jE(X{r&xxW+Bj{K{ov$IKD;TL;2*2lXuy3cVN0hsf^9&eRRsGyPI33qIWt0WSSy~
z+>5QjfXF(`?m9R*{e%Y24JANRyeHn#$VMgG6Aa&Pho;oABK@AFWkEo)Sd$}=-MZ=e
zqqfdWo8i%*CZ!-zW;p!Ov~!InUrJn?E747R#jbalT{0Doqtt`LhzmDF;6#)
zZV-BSc<5wGKDhz)4~~*X%q3dosCUs0374UFw8H+ePJP0J-})L8Bht#X
z<+hwI?f>a788jN8l%0v}*AFHX<>YQqV~mcCX&SEGXVrH!&DrjJ<8K|+*vNt#@@ylo
zG?f$V2mi_
zPtUe#V7>#I*&-an>up~OoIvY(KwT_)wiHMTV$iLm#-1{NE;5yMIcb!
zh5ePDkoWIf>Rb=_hTba0f^U^Fv^fd=q`0`);5yE2MsSox$yCto&?3+ucd}vtq}aw;
zmU`%&W6o$6-qYksOR$Cc`_KM!1&jSvR0b$br_13f9%4?co_=GN0l^pPJ%S)scEtle
zKL~&AU{1~@$h>|R(>>bTn?KrjXqna!x462Bfv|O%VU=-n6PaciNEX&GOn`BX%5aCv
z!s22gu$k2Vxs{?}fUSbu2cQQbp`pI<@$vG%VN^o>*|SW|9Ok4@H8u*t4a!fcsr^A)
zHrBsWlaqT3*B+hl+$1MQYCt-q?_W3xWPSbmb!h8*U0w1KdOSg72nGOntzhAeg>tYV
z;7*pMvr0@PPB~%O!y9wZ);-6~`w~YjlH!ca&Bybvq~ahGLEOg%-&3o^=mr2gOi@u$
zFuj+7ZcP9-(tUo~XL+K+;%Vuv0`n}?00*4nSg5HqZo!;D6Roa}&I7hP`~@iZ3B$-4
zE*M;CeD=P3ce`qS36w}XC#Nw*kr(Lt3
z`5gr|ik>4(p!y(Oe*bO+6HD{!goUr_zaKjSis?)3fprK2C;`uV{_Fr~I9}R-d8&kG
zcR*kuH%L3?J9*HydLwU(eg-p@7jXOo^R7?F17fsA&nxAiLWW4u8~kwI=|}oc4Nn~b
zZVZFl6V$rM1?AnA&+#|74c!O>AsT|R*Q4JX9}Aurf|6s1;6nOcc~{^UPQ-gcOh;s+
zZ4YJPqWK`-1wVp34)nrXtfCNf+11t6qg7czV`^0EbG-q2J_fG%bxo(@HTn5DNSqsT
z&(rImQnfDceFnPMn6II!`IA5Z)DeC+Nm#PAcd_*(Pu96Vh*Sc#^(rYMvA|YMnMk@s
z-D&6M=9H`4|F5CA(J}ONO{uP~Zs+XW5r9ql`*E;Jf{j{=
zNFZ3*8PIVf{t|PrvB^3(@Btp5{o|+1%tP+A-*q3U{{i6`-6v({~N6_a2K`$+cPJ!z7?Hd--K^z@5y;gGOMVhkL_b}H-a!E1p
zDAVog%b*EOTTXKUvv9RZ&RqJF^``GxwYy=l1sF~bR
z5}zfB)m=d7K4U_&6%+vv8DQ`Pf%F@xq6p_-#fa=h&`G{p)?LBs`;eH31Bf1E*?@q6
z@;~l(v*t0#uE9Y;4xE+>Hdej^*$&ZUp5{50?{Wma0Xc{hgijp=@T#IxrqUeF3Tfhp
zQwtIx=g(lJ0Cg9jCUWudjlgvBmld)GkZr+zocTj8f%ui^MV)9uAzxp()0X%AZJh^!6GV=fPoFaRRWkyd
zq*gt@jB2Q>`^tq;Fo4Agwgb2v&DR$L*9M>^Q$0UL?Cy2Y-2uD`r-Njd*p0*hEs-v#
znCm_|WYWFB`N#jcfEWMP(qOKo8C)4(jCV
z)sS4DH(pO0jYG%2N39(H7O$p68pJVHrMRkrY>>
-عموما میتوان مسئلههایی که از **توالی** انجام یک **کار یکسان** قابل حل هستند را به صورت بازگشتی پیادهسازی کرد. مراحل اجرای نمونه کد بالا به صورت زیر است::
+عموما میتوان مسئلههایی که از **توالی** انجام یک **کار یکسان** قابل حل هستند را به صورت بازگشتی پیادهسازی کرد. مراحل اجرای نمونه کد بالا به صورت زیر است:
+
+.. image:: /_static/l14-factorial-relation.png
+ :align: center
+
+::
factorial(5)
|--> 5 * factorial(4)
@@ -60,8 +65,22 @@
5 * (4 * (3 * (2 * 1)))
+**توضیح:** هنگامی factorial(5) فراخوانی میشود (``n == 5``)، شرط ``1 => n`` رد و بخش
+
**پیادهسازی شیوه بازگشتی شاید به نظر هیجانانگیز باشد اما نباید فراموش کرد که میزان حافظه (Memory) زیادی مصرف میکند، اجرای آن زمانبر خواهد بود، درک جریان اجرای آن اغلب سخت است و اشکالزدایی (debug) آن ساده نخواهد بود!**
+هر تابع بازگشتی شامل دو بخش مهم است:
+
+* یک عبارت حاوی فراخوانی خود تابع
+* یک شرط برای انتخاب بین بازگشت (فراخوانی مجدد) و پایان
+
+در مورد مثال محاسبه فاکتوریل، چنانچه شرط ``1 => n`` برقرار شود، عملیات به انتها میرسد.
+
+
+
+
+
+
From 18da6a733a439260a18c612f6a97c660c5f94488 Mon Sep 17 00:00:00 2001
From: Saeid
Date: Sat, 26 Oct 2019 14:04:53 +0330
Subject: [PATCH 032/294] work on Recursive
---
_static/l14-factorial-relation.png | Bin 15826 -> 14992 bytes
lessons/l14.rst | 46 +++++++++++++++++++++++++----
2 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/_static/l14-factorial-relation.png b/_static/l14-factorial-relation.png
index a1c127e12ba90abab796f7016d020e3568dea367..67bb1d53ae8115fb135875c8080d7c2942992efc 100644
GIT binary patch
literal 14992
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 def factorial(n):
... if n <= 1:
- ... return 1 # 0! == 1 and 1! == 1
+ ... return 1
... else:
... return n * factorial(n - 1)
...
@@ -63,20 +63,54 @@
|--> 2 * factorial(1)
|--> 1
- 5 * (4 * (3 * (2 * 1)))
+ 120 = 5 * (4 * (3 * (2 * 1)))
-**توضیح:** هنگامی factorial(5) فراخوانی میشود (``n == 5``)، شرط ``1 => n`` رد و بخش
+**توضیح:** هنگامی ``factorial(5)`` فراخوانی میشود (``n == 5``)، شرط ``1 => n`` رد و بخش ``else`` اجرا میشود. در این مرحله نمونه دیگری از تابع با آرگومان ``4`` فراخوانی میشود و اجرای ``factorial(5)`` منتظر پایان اجرای ``factorial(4)`` و دریافت نتیجه آن میماند. به همین ترتیب چندین نمونه از یک تابع اجرا میشوند که منتظر دریافت نتیجه از نمونه بعد از خود هستند. در نهایت شرط ``1 => n`` برقرار میشود و نمونه ``factorial(1)`` نتیجه خود را به ``factorial(2)`` برمیگرداند. به همین ترتیب نتایج بازگشت داده میشوند تا به نمونه نخست اجرا شده یعنی ``factorial(5)`` برسد و اجرای مورد نظر کاربر به پایان برسد.
-**پیادهسازی شیوه بازگشتی شاید به نظر هیجانانگیز باشد اما نباید فراموش کرد که میزان حافظه (Memory) زیادی مصرف میکند، اجرای آن زمانبر خواهد بود، درک جریان اجرای آن اغلب سخت است و اشکالزدایی (debug) آن ساده نخواهد بود!**
+مدیریت توالی تابع (شیوه بازگشتی) در حافظه با استفاده از ساختمان داده پشته (Stack) [`ویکیپدیا `__] انجام میشود.
هر تابع بازگشتی شامل دو بخش مهم است:
* یک عبارت حاوی فراخوانی خود تابع
-* یک شرط برای انتخاب بین بازگشت (فراخوانی مجدد) و پایان
+* یک شرط برای انتخاب بین فراخوانی مجدد و پایان
+
+**پیادهسازی شیوه بازگشتی شاید به نظر هیجانانگیز باشد اما نباید فراموش کرد که میزان حافظه (Memory) زیادی مصرف میکند، اجرای آن زمانبر خواهد بود، درک جریان اجرای آن اغلب سخت است و اشکالزدایی (debug) آن ساده نخواهد بود!**
+
+تنظیم عمق بازگشتی
+~~~~~~~~~~~~~~~~~~~~
+
+در زبان برنامهنویسی پایتون در عمق پیادهسازی توابع بازگشتی (تعداد نمونههای فراخوانی شده از تابع و موجود در پشته) یک محدودیت قابل تنظیم وجود دارد. تابع ``()getrecursionlimit`` از ماژول ``sys`` این مقدار را برمیگرداند [`اسناد پایتون `__]. این مقدار به صورت پیشفرض برابر با ``1000`` میباشد که با استفاده از تابع ``(limit)setrecursionlimit`` از ماژول ``sys`` میتوان آن را تغییر داد [`اسناد پایتون