From 4dcdc8c880e41b5c3a9f5ca49208d991937782b6 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 5 Dec 2025 07:58:40 +1100 Subject: [PATCH 1/7] =?UTF-8?q?Add=20lecture:=20=D9=86=D8=A7=D9=85?= =?UTF-8?q?=E2=80=8C=D9=87=D8=A7=20=D9=88=20=D9=81=D8=B6=D8=A7=D9=87=D8=A7?= =?UTF-8?q?=DB=8C=20=D9=86=D8=A7=D9=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lectures/names.md | 570 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 570 insertions(+) create mode 100644 lectures/names.md diff --git a/lectures/names.md b/lectures/names.md new file mode 100644 index 0000000..28a6274 --- /dev/null +++ b/lectures/names.md @@ -0,0 +1,570 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +heading-map: + overview: مرور کلی + variable-names-in-python: نام‌های متغیر در Python + namespaces: فضاهای نام + viewing-namespaces: مشاهده فضاهای نام + interactive-sessions: جلسات تعاملی + the-global-namespace: فضای نام عمومی + local-namespaces: فضاهای نام محلی + the-__builtins__-namespace: فضای نام `__builtins__` + name-resolution: تفکیک نام + indexmutable-single-mutable-versus-indeximmutable-single-immutable-parameters: 'پارامترهای {index}`تغییرپذیر ` در مقابل {index}`تغییرناپذیر `' +--- + +(oop_names)= +```{raw} jupyter + +``` + +# نام‌ها و فضاهای نام + +## مرور کلی + +این درس تماماً درباره نام‌های متغیر، نحوه استفاده از آن‌ها و نحوه درک آن‌ها توسط مفسر Python است. + +ممکن است این موضوع کمی خسته‌کننده به نظر برسد، اما مدلی که Python برای مدیریت نام‌ها اتخاذ کرده است، ظریف و جالب است. + +علاوه بر این، اگر درک خوبی از نحوه کار نام‌ها در Python داشته باشید، ساعت‌های زیادی را از اشکال‌زدایی صرفه‌جویی خواهید کرد. + +(var_names)= +## نام‌های متغیر در Python + +```{index} single: Python; Variable Names +``` + +دستور Python زیر را در نظر بگیرید + +```{code-cell} python3 +x = 42 +``` + +اکنون می‌دانیم که وقتی این دستور اجرا می‌شود، Python یک شیء از نوع `int` در حافظه کامپیوتر شما ایجاد می‌کند که شامل موارد زیر است: + +* مقدار `42` +* برخی صفات مرتبط + +اما خود `x` چیست؟ + +در Python، `x` یک **نام** نامیده می‌شود، و دستور `x = 42` نام `x` را به شیء عدد صحیح که تازه در موردش صحبت کردیم **متصل** می‌کند. + +در پشت صحنه، این فرآیند اتصال نام‌ها به اشیاء به عنوان یک دیکشنری پیاده‌سازی می‌شود - بیشتر درباره این موضوع در ادامه خواهیم گفت. + +هیچ مشکلی برای اتصال دو یا چند نام به یک شیء وجود ندارد، صرف‌نظر از اینکه آن شیء چه باشد + +```{code-cell} python3 +def f(string): # Create a function called f + print(string) # that prints any string it's passed + +g = f +id(g) == id(f) +``` + +```{code-cell} python3 +g('test') +``` + +در مرحله اول، یک شیء تابع ایجاد می‌شود و نام `f` به آن متصل می‌شود. + +پس از اتصال نام `g` به همان شیء، می‌توانیم از آن در هر جایی که از `f` استفاده می‌کنیم، استفاده کنیم. + +وقتی تعداد نام‌های متصل به یک شیء به صفر می‌رسد، چه اتفاقی می‌افتد؟ + +در اینجا مثالی از این وضعیت آورده شده است، که در آن نام `x` ابتدا به یک شیء متصل می‌شود و سپس به شیء دیگری **دوباره متصل** می‌شود + +```{code-cell} python3 +x = 'foo' +id(x) +x = 'bar' +id(x) +``` + +در این مورد، پس از اینکه `x` را مجدداً به `'bar'` متصل می‌کنیم، هیچ نامی به شیء اول `'foo'` متصل نیست. + +این یک محرک برای جمع‌آوری زباله `'foo'` است. + +به عبارت دیگر، جای حافظه‌ای که آن شیء را ذخیره می‌کند، آزاد می‌شود و به سیستم عامل بازگردانده می‌شود. + +جمع‌آوری زباله در واقع یک حوزه تحقیقاتی فعال در علوم کامپیوتر است. + +اگر علاقه‌مند هستید، می‌توانید [بیشتر درباره جمع‌آوری زباله بخوانید](https://rushter.com/blog/python-garbage-collector/). + +## فضاهای نام + +```{index} single: Python; Namespaces +``` + +از بحث قبلی به یاد بیاورید که دستور + +```{code-cell} python3 +x = 42 +``` + +نام `x` را به شیء عدد صحیح در سمت راست متصل می‌کند. + +همچنین ذکر کردیم که این فرآیند اتصال `x` به شیء صحیح به عنوان یک دیکشنری پیاده‌سازی می‌شود. + +این دیکشنری، فضای نام نامیده می‌شود. + +```{admonition} تعریف +یک **فضای نام** یک جدول نمادها است که نام‌ها را به اشیاء در حافظه نگاشت می‌کند. +``` + +Python از چندین فضای نام استفاده می‌کند و در صورت لزوم آن‌ها را به صورت پویا ایجاد می‌کند. + +به عنوان مثال، هر بار که ماژولی را import می‌کنیم، Python یک فضای نام برای آن ماژول ایجاد می‌کند. + +برای مشاهده این موضوع در عمل، فرض کنید یک اسکریپت `mathfoo.py` با یک خط می‌نویسیم + +```{code-cell} python3 +%%file mathfoo.py +pi = 'foobar' +``` + +حالا مفسر Python را شروع می‌کنیم و آن را import می‌کنیم + +```{code-cell} python3 +import mathfoo +``` + +بعد بیایید ماژول `math` را از کتابخانه استاندارد import کنیم + +```{code-cell} python3 +import math +``` + +هر دوی این ماژول‌ها یک صفت به نام `pi` دارند + +```{code-cell} python3 +math.pi +``` + +```{code-cell} python3 +mathfoo.pi +``` + +این دو اتصال متفاوت `pi` در فضاهای نام متفاوتی وجود دارند که هر کدام به عنوان یک دیکشنری پیاده‌سازی شده‌اند. + +اگر بخواهید، می‌توانید مستقیماً به دیکشنری نگاه کنید، با استفاده از `module_name.__dict__`. + +```{code-cell} python3 +import math + +math.__dict__.items() +``` + +```{code-cell} python3 +import mathfoo + +mathfoo.__dict__ +``` + +همان‌طور که می‌دانید، ما با استفاده از نشانه‌گذاری صفت نقطه‌دار به عناصر فضای نام دسترسی پیدا می‌کنیم + +```{code-cell} python3 +math.pi +``` + +این کاملاً معادل `math.__dict__['pi']` است + +```{code-cell} python3 +math.__dict__['pi'] +``` + +## مشاهده فضاهای نام + +همان‌طور که در بالا دیدیم، فضای نام `math` را می‌توان با تایپ کردن `math.__dict__` چاپ کرد. + +راه دیگر برای دیدن محتویات آن تایپ کردن `vars(math)` است + +```{code-cell} python3 +vars(math).items() +``` + +اگر فقط می‌خواهید نام‌ها را ببینید، می‌توانید تایپ کنید + +```{code-cell} python3 +# Show the first 10 names +dir(math)[0:10] +``` + +به نام‌های ویژه `__doc__` و `__name__` توجه کنید. + +این‌ها در فضای نام هنگام import کردن هر ماژول مقداردهی اولیه می‌شوند + +* `__doc__` رشته مستندسازی ماژول است +* `__name__` نام ماژول است + +```{code-cell} python3 +print(math.__doc__) +``` + +```{code-cell} python3 +math.__name__ +``` + +## جلسات تعاملی + +```{index} single: Python; Interpreter +``` + +در Python، **تمام** کدهایی که توسط مفسر اجرا می‌شوند در ماژولی اجرا می‌شوند. + +در مورد دستوراتی که در prompt تایپ می‌شوند چطور؟ + +این‌ها نیز به عنوان اجرا شده در یک ماژول در نظر گرفته می‌شوند - در این مورد، ماژولی به نام `__main__`. + +برای بررسی این موضوع، می‌توانیم نام ماژول فعلی را از طریق مقدار `__name__` که در prompt داده می‌شود مشاهده کنیم + +```{code-cell} python3 +print(__name__) +``` + +وقتی یک اسکریپت را با استفاده از دستور `run` در IPython اجرا می‌کنیم، محتویات فایل نیز به عنوان بخشی از `__main__` اجرا می‌شوند. + +برای مشاهده این موضوع، بیایید یک فایل `mod.py` ایجاد کنیم که صفت `__name__` خودش را چاپ کند + +```{code-cell} ipython +%%file mod.py +print(__name__) +``` + +حالا بیایید دو روش متفاوت اجرای آن را در IPython ببینیم + +```{code-cell} python3 +import mod # Standard import +``` + +```{code-cell} ipython +%run mod.py # Run interactively +``` + +در حالت دوم، کد به عنوان بخشی از `__main__` اجرا می‌شود، بنابراین `__name__` برابر با `__main__` است. + +برای دیدن محتویات فضای نام `__main__` از `vars()` به جای `vars(__main__)` استفاده می‌کنیم. + +اگر این کار را در IPython انجام دهید، تعداد زیادی متغیر خواهید دید که IPython به آن‌ها نیاز دارد و هنگام شروع جلسه مقداردهی اولیه کرده است. + +اگر ترجیح می‌دهید فقط متغیرهایی که شما مقداردهی اولیه کرده‌اید را ببینید، از `%whos` استفاده کنید + +```{code-cell} ipython +x = 2 +y = 3 + +import numpy as np + +%whos +``` + +## فضای نام عمومی + +```{index} single: Python; Namespace (Global) +``` + +مستندات Python اغلب به "فضای نام عمومی" اشاره می‌کند. + +فضای نام عمومی *فضای نام ماژولی است که در حال حاضر در حال اجرا است*. + +به عنوان مثال، فرض کنید که مفسر را شروع می‌کنیم و شروع به انجام انتسابات می‌کنیم. + +اکنون ما در ماژول `__main__` کار می‌کنیم، و از این رو فضای نام برای `__main__` فضای نام عمومی است. + +سپس، ماژولی به نام `amodule` را import می‌کنیم + +```{code-block} python3 +:class: no-execute + +import amodule +``` + +در این نقطه، مفسر یک فضای نام برای ماژول `amodule` ایجاد می‌کند و شروع به اجرای دستورات در ماژول می‌کند. + +در حالی که این اتفاق می‌افتد، فضای نام `amodule.__dict__` فضای نام عمومی است. + +پس از اتمام اجرای ماژول، مفسر به ماژولی که دستور import از آن صادر شده بود بازمی‌گردد. + +در این مورد `__main__` است، بنابراین فضای نام `__main__` دوباره فضای نام عمومی می‌شود. + +## فضاهای نام محلی + +```{index} single: Python; Namespace (Local) +``` + +نکته مهم: وقتی یک تابع را فراخوانی می‌کنیم، مفسر یک *فضای نام محلی* برای آن تابع ایجاد می‌کند و متغیرها را در آن فضای نام ثبت می‌کند. + +دلیل این امر در همین لحظه توضیح داده خواهد شد. + +متغیرهای موجود در فضای نام محلی *متغیرهای محلی* نامیده می‌شوند. + +پس از بازگشت تابع، فضای نام آزاد می‌شود و از بین می‌رود. + +در حالی که تابع در حال اجرا است، می‌توانیم محتویات فضای نام محلی را با `locals()` مشاهده کنیم. + +به عنوان مثال، در نظر بگیرید + +```{code-cell} python3 +def f(x): + a = 2 + print(locals()) + return a * x +``` + +حالا بیایید تابع را فراخوانی کنیم + +```{code-cell} python3 +f(1) +``` + +می‌توانید فضای نام محلی `f` را قبل از نابود شدن ببینید. + +## فضای نام `__builtins__` + +```{index} single: Python; Namespace (__builtins__) +``` + +ما از توابع داخلی مختلفی مانند `max(), dir(), str(), list(), len(), range(), type()` و غیره استفاده کرده‌ایم. + +دسترسی به این نام‌ها چگونه کار می‌کند؟ + +* این تعاریف در ماژولی به نام `__builtin__` ذخیره شده‌اند. +* آن‌ها فضای نام خاص خود را به نام `__builtins__` دارند. + +```{code-cell} python3 +# Show the first 10 names in `__main__` +dir()[0:10] +``` + +```{code-cell} python3 +# Show the first 10 names in `__builtins__` +dir(__builtins__)[0:10] +``` + +می‌توانیم به عناصر فضای نام به صورت زیر دسترسی پیدا کنیم + +```{code-cell} python3 +__builtins__.max +``` + +اما `__builtins__` ویژه است، زیرا همیشه می‌توانیم مستقیماً به آن‌ها نیز دسترسی پیدا کنیم + +```{code-cell} python3 +max +``` + +```{code-cell} python3 +__builtins__.max == max +``` + +بخش بعدی توضیح می‌دهد که این چگونه کار می‌کند ... + +## تفکیک نام + +```{index} single: Python; Namespace (Resolution) +``` + +فضاهای نام عالی هستند زیرا به ما کمک می‌کنند تا نام‌های متغیر را سازماندهی کنیم. + +(در prompt عبارت `import this` را تایپ کنید و به آخرین موردی که چاپ می‌شود نگاه کنید) + +با این حال، ما باید بفهمیم که مفسر Python چگونه با فضاهای نام متعدد کار می‌کند. + +درک جریان اجرا به ما کمک می‌کند تا بررسی کنیم که کدام متغیرها در محدوده هستند و چگونه می‌توانیم هنگام نوشتن و اشکال‌زدایی برنامه‌ها بر روی آن‌ها عمل کنیم. + +در هر نقطه از اجرا، در واقع حداقل دو فضای نام وجود دارند که می‌توان به طور مستقیم به آن‌ها دسترسی پیدا کرد. + +("دسترسی مستقیم" به معنای بدون استفاده از نقطه است، مانند `pi` به جای `math.pi`) + +این فضاهای نام عبارتند از + +* فضای نام عمومی (ماژولی که در حال اجرا است) +* فضای نام builtin + +اگر مفسر در حال اجرای یک تابع است، آنگاه فضاهای نام قابل دسترسی مستقیم عبارتند از + +* فضای نام محلی تابع +* فضای نام عمومی (ماژولی که در حال اجرا است) +* فضای نام builtin + +گاهی اوقات توابع در داخل توابع دیگر تعریف می‌شوند، مانند این + +```{code-cell} python3 +def f(): + a = 2 + def g(): + b = 4 + print(a * b) + g() +``` + +در اینجا `f` تابع *احاطه‌کننده* برای `g` است و هر تابع فضای نام خود را دارد. + +حالا می‌توانیم قانون نحوه کار تفکیک فضای نام را بیان کنیم: + +ترتیبی که مفسر برای جستجوی نام‌ها دنبال می‌کند عبارت است از + +1. فضای نام محلی (اگر وجود داشته باشد) +1. سلسله مراتب فضاهای نام احاطه‌کننده (اگر وجود داشته باشند) +1. فضای نام عمومی +1. فضای نام builtin + +اگر نام در هیچ یک از این فضاهای نام نباشد، مفسر یک `NameError` ایجاد می‌کند. + +این قانون **LEGB** نامیده می‌شود (local, enclosing, global, builtin). + +در اینجا مثالی آورده شده است که کمک می‌کند تا توضیح داده شود. + +تجسم‌های اینجا توسط [nbtutor](https://github.com/lgpage/nbtutor) در یک نوت‌بوک Jupyter ایجاد شده‌اند. + +آن‌ها می‌توانند به شما کمک کنند تا برنامه خود را بهتر درک کنید وقتی که در حال یادگیری یک زبان جدید هستید. + +اسکریپت `test.py` را در نظر بگیرید که به صورت زیر است + +```{code-cell} python3 +%%file test.py +def g(x): + a = 1 + x = x + a + return x + +a = 0 +y = g(10) +print("a = ", a, "y = ", y) +``` + +وقتی این اسکریپت را اجرا می‌کنیم، چه اتفاقی می‌افتد؟ + +```{code-cell} ipython +%run test.py +``` + +ابتدا، + +* فضای نام عمومی `{}` ایجاد می‌شود. + +```{figure} /_static/lecture_specific/oop_intro/global.png +``` + +* شیء تابع ایجاد می‌شود و `g` در فضای نام عمومی به آن متصل می‌شود. +* نام `a` به `0` متصل می‌شود، دوباره در فضای نام عمومی. + +```{figure} /_static/lecture_specific/oop_intro/global2.png +``` + +بعد `g` از طریق `y = g(10)` فراخوانی می‌شود که منجر به توالی زیر از اقدامات می‌شود + +* فضای نام محلی برای تابع ایجاد می‌شود. +* نام‌های محلی `x` و `a` متصل می‌شوند، به طوری که فضای نام محلی به `{'x': 10, 'a': 1}` تبدیل می‌شود. + +توجه کنید که `a` عمومی تحت تأثیر `a` محلی قرار نگرفت. + +```{figure} /_static/lecture_specific/oop_intro/local1.png +``` + +* دستور `x = x + a` از `a` محلی و `x` محلی برای محاسبه `x + a` استفاده می‌کند و نام محلی `x` را به نتیجه متصل می‌کند. +* این مقدار بازگردانده می‌شود و `y` در فضای نام عمومی به آن متصل می‌شود. +* `x` و `a` محلی دور انداخته می‌شوند (و فضای نام محلی آزاد می‌شود). + +```{figure} /_static/lecture_specific/oop_intro/local_return.png +``` + +(mutable_vs_immutable)= +### پارامترهای {index}`تغییرپذیر ` در مقابل {index}`تغییرناپذیر ` + +این زمان خوبی است که کمی بیشتر درباره اشیاء تغییرپذیر در مقابل تغییرناپذیر صحبت کنیم. + +بخش کد زیر را در نظر بگیرید + +```{code-cell} python3 +def f(x): + x = x + 1 + return x + +x = 1 +print(f(x), x) +``` + +اکنون می‌فهمیم که اینجا چه اتفاقی می‌افتد: کد `2` را به عنوان مقدار `f(x)` و `1` را به عنوان مقدار `x` چاپ می‌کند. + +ابتدا `f` و `x` در فضای نام عمومی ثبت می‌شوند. + +فراخوانی `f(x)` یک فضای نام محلی ایجاد می‌کند و `x` را به آن اضافه می‌کند که به `1` متصل است. + +بعد، این `x` محلی به شیء عدد صحیح جدید `2` دوباره متصل می‌شود و این مقدار بازگردانده می‌شود. + +هیچ یک از این‌ها بر `x` عمومی تأثیر نمی‌گذارد. + +با این حال، وقتی از یک نوع داده **تغییرپذیر** مانند لیست استفاده می‌کنیم، داستان متفاوت است + +```{code-cell} python3 +def f(x): + x[0] = x[0] + 1 + return x + +x = [1] +print(f(x), x) +``` + +این `[2]` را به عنوان مقدار `f(x)` و *همان* را برای `x` چاپ می‌کند. + +در اینجا چه اتفاقی می‌افتد + +* `f` به عنوان یک تابع در فضای نام عمومی ثبت می‌شود + +```{figure} /_static/lecture_specific/oop_intro/mutable1.png +``` + +* `x` به `[1]` در فضای نام عمومی متصل می‌شود + +```{figure} /_static/lecture_specific/oop_intro/mutable2.png +``` + +* فراخوانی `f(x)` + * یک فضای نام محلی ایجاد می‌کند + * `x` را به فضای نام محلی اضافه می‌کند که به `[1]` متصل است + +```{figure} /_static/lecture_specific/oop_intro/mutable3.png +``` + +```{note} +`x` عمومی و `x` محلی به همان `[1]` اشاره می‌کنند +``` + +می‌توانیم ببینیم که هویت `x` محلی و هویت `x` عمومی یکسان است + +```{code-cell} python3 +def f(x): + x[0] = x[0] + 1 + print(f'the identity of local x is {id(x)}') + return x + +x = [1] +print(f'the identity of global x is {id(x)}') +print(f(x), x) +``` + +* در داخل `f(x)` + * لیست `[1]` به `[2]` تغییر می‌کند + * لیست `[2]` را برمی‌گرداند + +```{figure} /_static/lecture_specific/oop_intro/mutable4.png +``` +* فضای نام محلی آزاد می‌شود و `x` محلی از بین می‌رود + +```{figure} /_static/lecture_specific/oop_intro/mutable5.png +``` + +اگر می‌خواهید `x` محلی و `x` عمومی را به طور جداگانه تغییر دهید، می‌توانید یک [*کپی*](https://docs.python.org/3/library/copy.html) از لیست ایجاد کنید و کپی را به `x` محلی اختصاص دهید. + +این را برای شما برای کاوش باقی می‌گذاریم. \ No newline at end of file From 8ea8cfeedea9605717c67f125f5c9006a2e60302 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 5 Dec 2025 07:58:46 +1100 Subject: [PATCH 2/7] =?UTF-8?q?Add=20lecture:=20OOP=20I:=20=D8=A7=D8=B4?= =?UTF-8?q?=DB=8C=D8=A7=D8=A1=20=D9=88=20=D9=85=D8=AA=D8=AF=D9=87=D8=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lectures/oop_intro.md | 402 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 lectures/oop_intro.md diff --git a/lectures/oop_intro.md b/lectures/oop_intro.md new file mode 100644 index 0000000..dcd8d7f --- /dev/null +++ b/lectures/oop_intro.md @@ -0,0 +1,402 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +heading-map: + overview: مروری کلی + objects: اشیاء + type: نوع + identity: شناسه + object-content-data-and-attributes: 'محتوای شیء: داده‌ها و ویژگی‌ها' + methods: متدها + inspection-using-rich: بازرسی با استفاده از Rich + a-little-mystery: یک معمای کوچک + summary: خلاصه + exercises: تمرین‌ها +--- + +(oop_intro)= +```{raw} jupyter + +``` + +# OOP I: اشیاء و متدها + +## مروری کلی + +پارادایم سنتی برنامه‌نویسی (مانند Fortran، C، MATLAB و غیره) [رویه‌ای](https://en.wikipedia.org/wiki/Procedural_programming) نامیده می‌شود. + +این پارادایم به شرح زیر عمل می‌کند + +* برنامه دارای یک وضعیت متناظر با مقادیر متغیرهای خود است. +* توابع فراخوانی می‌شوند تا بر روی وضعیت عمل کرده و آن را تغییر دهند. +* خروجی‌های نهایی از طریق توالی‌ای از فراخوانی‌های تابع تولید می‌شوند. + +دو پارادایم مهم دیگر، [برنامه‌نویسی شی‌گرا](https://en.wikipedia.org/wiki/Object-oriented_programming) (OOP) و [برنامه‌نویسی تابعی](https://en.wikipedia.org/wiki/Functional_programming) هستند. + +در پارادایم OOP، داده‌ها و توابع با هم در "اشیاء" بسته‌بندی می‌شوند --- و توابع در این زمینه به عنوان **متدها** شناخته می‌شوند. + +متدها برای تغییر داده‌های موجود در شیء فراخوانی می‌شوند. + +* به یک لیست Python فکر کنید که حاوی داده است و متدهایی مانند `append()` و `pop()` دارد که داده را تغییر می‌دهند. + +زبان‌های برنامه‌نویسی تابعی بر اساس ایده ترکیب توابع ساخته شده‌اند. + +* نمونه‌های تأثیرگذار شامل [Lisp](https://en.wikipedia.org/wiki/Common_Lisp)، [Haskell](https://en.wikipedia.org/wiki/Haskell) و [Elixir](https://en.wikipedia.org/wiki/Elixir_(programming_language)) هستند. + +پس Python در کدام یک از این دسته‌ها قرار می‌گیرد؟ + +در واقع Python یک زبان عمل‌گرا است که سبک‌های شی‌گرا، تابعی و رویه‌ای را ترکیب می‌کند، به جای اینکه رویکردی خالص داشته باشد. + +از یک طرف، این امکان را به Python و کاربران آن می‌دهد تا جنبه‌های خوب پارادایم‌های مختلف را انتخاب کنند. + +از طرف دیگر، فقدان خلوص ممکن است گاهی اوقات منجر به برخی سردرگمی‌ها شود. + +خوشبختانه این سردرگمی به حداقل می‌رسد اگر درک کنید که، در سطح بنیادی، Python شی‌گرا *است*. + +منظور ما این است که، در Python، *همه چیز یک شیء است*. + +در این سخنرانی، توضیح می‌دهیم که این گزاره به چه معناست و چرا اهمیت دارد. + +ما از کتابخانه شخص ثالث زیر استفاده خواهیم کرد + +```{code-cell} python3 +:tags: [hide-output] +!pip install rich +``` + +## اشیاء + +```{index} single: Python; Objects +``` + +در Python، یک *شیء* مجموعه‌ای از داده‌ها و دستورالعمل‌های نگهداری‌شده در حافظه کامپیوتر است که شامل موارد زیر می‌شود + +1. یک نوع +1. یک شناسه منحصر به فرد +1. داده (یعنی محتوا) +1. متدها + +این مفاهیم به ترتیب تعریف و بحث می‌شوند. + +(type)= +### نوع + +```{index} single: Python; Type +``` + +Python برای انواع مختلف اشیاء فراهم می‌کند تا دسته‌های مختلف داده را در بر گیرد. + +به عنوان مثال + +```{code-cell} python3 +s = 'This is a string' +type(s) +``` + +```{code-cell} python3 +x = 42 # حالا بیایید یک عدد صحیح ایجاد کنیم +type(x) +``` + +نوع یک شیء برای بسیاری از عبارات مهم است. + +به عنوان مثال، عملگر جمع بین دو رشته به معنای الحاق است + +```{code-cell} python3 +'300' + 'cc' +``` + +از طرف دیگر، بین دو عدد به معنای جمع معمولی است + +```{code-cell} python3 +300 + 400 +``` + +عبارت زیر را در نظر بگیرید + +```{code-cell} python3 +--- +tags: [raises-exception] +--- +'300' + 400 +``` + +در اینجا ما در حال ترکیب انواع هستیم، و برای Python مشخص نیست که آیا کاربر می‌خواهد + +* `'300'` را به عدد صحیح تبدیل کند و سپس آن را به `400` اضافه کند، یا +* `400` را به رشته تبدیل کند و سپس آن را با `'300'` الحاق کند + +برخی زبان‌ها ممکن است سعی کنند حدس بزنند اما Python *به شدت تایپ‌شده* است + +* نوع مهم است، و تبدیل ضمنی نوع نادر است. +* Python در عوض با بالا آوردن یک `TypeError` پاسخ می‌دهد. + +برای جلوگیری از خطا، باید با تغییر نوع مربوطه توضیح دهید. + +به عنوان مثال، + +```{code-cell} python3 +int('300') + 400 # برای جمع به عنوان اعداد، رشته را به عدد صحیح تبدیل کنید +``` + +(identity)= +### شناسه + +```{index} single: Python; Identity +``` + +در Python، هر شیء یک شناسه منحصر به فرد دارد که به Python (و ما) کمک می‌کند تا شیء را پیگیری کند. + +شناسه یک شیء را می‌توان از طریق تابع `id()` به دست آورد + +```{code-cell} python3 +y = 2.5 +z = 2.5 +id(y) +``` + +```{code-cell} python3 +id(z) +``` + +در این مثال، `y` و `z` اتفاقاً مقدار یکسانی (یعنی `2.5`) دارند، اما آن‌ها یک شیء نیستند. + +شناسه یک شیء در واقع فقط آدرس شیء در حافظه است. + +### محتوای شیء: داده‌ها و ویژگی‌ها + +```{index} single: Python; Content +``` + +اگر `x = 42` را تنظیم کنیم، یک شیء از نوع `int` ایجاد می‌کنیم که حاوی داده `42` است. + +در واقع، حاوی چیزهای بیشتری است، همانطور که مثال زیر نشان می‌دهد + +```{code-cell} python3 +x = 42 +x +``` + +```{code-cell} python3 +x.imag +``` + +```{code-cell} python3 +x.__class__ +``` + +وقتی Python این شیء عدد صحیح را ایجاد می‌کند، اطلاعات کمکی مختلفی مانند قسمت موهومی و نوع را با آن ذخیره می‌کند. + +هر نامی که بعد از نقطه می‌آید یک *ویژگی* از شیء سمت چپ نقطه نامیده می‌شود. + +* به عنوان مثال، `imag` و `__class__` ویژگی‌های `x` هستند. + +از این مثال می‌بینیم که اشیاء دارای ویژگی‌هایی هستند که حاوی اطلاعات کمکی هستند. + +آن‌ها همچنین دارای ویژگی‌هایی هستند که مانند توابع عمل می‌کنند، به نام *متدها*. + +این ویژگی‌ها مهم هستند، بنابراین بیایید آن‌ها را به طور عمیق بحث کنیم. + +(methods)= +### متدها + +```{index} single: Python; Methods +``` + +متدها *توابعی هستند که با اشیاء بسته‌بندی می‌شوند*. + +به طور رسمی، متدها ویژگی‌های اشیاء هستند که **قابل فراخوانی** هستند -- یعنی ویژگی‌هایی که می‌توانند به عنوان تابع فراخوانی شوند + +```{code-cell} python3 +x = ['foo', 'bar'] +callable(x.append) +``` + +```{code-cell} python3 +callable(x.__doc__) +``` + +متدها معمولاً بر روی داده‌های موجود در شیئی که به آن تعلق دارند عمل می‌کنند، یا آن داده را با داده‌های دیگر ترکیب می‌کنند + +```{code-cell} python3 +x = ['a', 'b'] +x.append('c') +s = 'This is a string' +s.upper() +``` + +```{code-cell} python3 +s.lower() +``` + +```{code-cell} python3 +s.replace('This', 'That') +``` + +بخش بزرگی از قابلیت‌های Python حول فراخوانی‌های متد سازماندهی شده است. + +به عنوان مثال، کد زیر را در نظر بگیرید + +```{code-cell} python3 +x = ['a', 'b'] +x[0] = 'aa' # انتساب آیتم با استفاده از نماد براکت مربعی +x +``` + +به نظر نمی‌رسد که در اینجا از هیچ متدی استفاده شده باشد، اما در واقع نماد انتساب براکت مربعی فقط یک رابط راحت برای فراخوانی متد است. + +آنچه در واقع اتفاق می‌افتد این است که Python متد `__setitem__` را فراخوانی می‌کند، به شرح زیر + +```{code-cell} python3 +x = ['a', 'b'] +x.__setitem__(0, 'aa') # معادل x[0] = 'aa' +x +``` + +(اگر بخواهید می‌توانید متد `__setitem__` را تغییر دهید، به طوری که انتساب براکت مربعی کار کاملاً متفاوتی انجام دهد) + +## بازرسی با استفاده از Rich + +یک بسته خوب به نام [rich](https://github.com/Textualize/rich) وجود دارد که به ما کمک می‌کند محتویات یک شیء را مشاهده کنیم. + +به عنوان مثال، + +```{code-cell} python3 +from rich import inspect +x = 10 +inspect(10) +``` +اگر بخواهیم متدها را نیز ببینیم، می‌توانیم استفاده کنیم + +```{code-cell} python3 +inspect(10, methods=True) +``` + +در واقع متدهای بیشتری وجود دارند، همانطور که می‌توانید ببینید اگر `inspect(10, all=True)` را اجرا کنید. + +## یک معمای کوچک + +در این سخنرانی ادعا کردیم که Python، در قلب، یک زبان شی‌گرا است. + +اما در اینجا مثالی وجود دارد که بیشتر رویه‌ای به نظر می‌رسد. + +```{code-cell} python3 +x = ['a', 'b'] +m = len(x) +m +``` + +اگر Python شی‌گرا است، چرا از `x.len()` استفاده نمی‌کنیم؟ + +پاسخ به این واقعیت مربوط است که Python برای خوانایی و سبک ثابت تلاش می‌کند. + +در Python، معمول است که کاربران اشیاء سفارشی بسازند --- ما نحوه انجام این کار را {doc}`بعداً ` بحث می‌کنیم. + +کاملاً رایج است که کاربران متدهایی به اشیاء خود اضافه کنند که طول شیء را، به طور مناسب تعریف شده، اندازه‌گیری کنند. + +هنگام نام‌گذاری چنین متدی، انتخاب‌های طبیعی `len()` و `length()` هستند. + +اگر برخی از کاربران `len()` و دیگران `length()` را انتخاب کنند، سبک ناسازگار و سخت‌تر برای به خاطر سپردن خواهد بود. + +برای جلوگیری از این امر، سازنده Python تصمیم گرفت `len()` را به عنوان یک تابع داخلی اضافه کند، تا به تأکید بر اینکه `len()` قرارداد است کمک کند. + +حالا، با گفتن همه این‌ها، Python همچنان در زیر پوشش شی‌گرا *است*. + +در واقع، لیست `x` مورد بحث بالا دارای متدی به نام `__len__()` است. + +تنها کاری که تابع `len()` انجام می‌دهد فراخوانی این متد است. + +به عبارت دیگر، کد زیر معادل است: + +```{code-cell} python3 +x = ['a', 'b'] +len(x) +``` +و + +```{code-cell} python3 +x = ['a', 'b'] +x.__len__() +``` + +## خلاصه + +پیام این سخنرانی واضح است: + +* در Python، *همه چیز در حافظه به عنوان یک شیء در نظر گرفته می‌شود*. + +این شامل نه فقط لیست‌ها، رشته‌ها و غیره، بلکه چیزهای کمتر آشکار، مانند + +* توابع (پس از خواندن در حافظه) +* ماژول‌ها (همان‌طور) +* فایل‌های باز شده برای خواندن یا نوشتن +* اعداد صحیح و غیره + +به یاد داشتن اینکه همه چیز یک شیء است به شما کمک می‌کند تا با برنامه‌های خود تعامل کنید و کد Pythonic واضحی بنویسید. + +## تمرین‌ها + +```{exercise-start} +:label: oop_intro_ex1 +``` + +ما قبلاً با {any}`نوع داده بولین ` آشنا شدیم. + +با استفاده از آنچه در این سخنرانی آموختیم، لیستی از متدهای شیء بولین `True` را چاپ کنید. + +```{hint} +:class: dropdown + +می‌توانید از `callable()` برای آزمایش اینکه آیا یک ویژگی از یک شیء می‌تواند به عنوان تابع فراخوانی شود، استفاده کنید +``` + +```{exercise-end} +``` + +```{solution-start} oop_intro_ex1 +:class: dropdown +``` + +ابتدا، باید همه ویژگی‌های `True` را پیدا کنیم، که می‌تواند از طریق این انجام شود + +```{code-cell} python3 +print(sorted(True.__dir__())) +``` + +یا + +```{code-cell} python3 +print(sorted(dir(True))) +``` + +از آنجایی که نوع داده بولین یک نوع اولیه است، می‌توانید آن را در فضای نام داخلی نیز پیدا کنید + +```{code-cell} python3 +print(dir(__builtins__.bool)) +``` + +در اینجا از یک حلقه `for` برای فیلتر کردن ویژگی‌هایی که قابل فراخوانی هستند استفاده می‌کنیم + +```{code-cell} python3 +attributes = dir(__builtins__.bool) +callablels = [] + +for attribute in attributes: + # از eval() برای ارزیابی یک رشته به عنوان یک عبارت استفاده کنید + if callable(eval(f'True.{attribute}')): + callablels.append(attribute) +print(callablels) +``` + +```{solution-end} +``` \ No newline at end of file From fc4b83ef6745dbe94b6e657edb4c2d4b5fce574f Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 5 Dec 2025 07:58:51 +1100 Subject: [PATCH 3/7] =?UTF-8?q?Add=20lecture:=20=D8=A7=D8=B5=D9=88=D9=84?= =?UTF-8?q?=20Python?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lectures/python_essentials.md | 1091 +++++++++++++++++++++++++++++++++ 1 file changed, 1091 insertions(+) create mode 100644 lectures/python_essentials.md diff --git a/lectures/python_essentials.md b/lectures/python_essentials.md new file mode 100644 index 0000000..fe7cfc2 --- /dev/null +++ b/lectures/python_essentials.md @@ -0,0 +1,1091 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +heading-map: + overview: مرور کلی + data-types: انواع داده + primitive-data-types: انواع داده ابتدایی + boolean-values: مقادیر Boolean + numeric-types: انواع عددی + containers: ظروف + slice-notation: نشانه‌گذاری Slice + sets-and-dictionaries: Set‌ها و Dictionary‌ها + input-and-output: ورودی و خروجی + paths: مسیرها + iterating: تکرار + looping-over-different-objects: حلقه زدن روی اشیاء مختلف + looping-without-indices: حلقه زدن بدون ایندکس‌ها + list-comprehensions: List Comprehension‌ها + comparisons-and-logical-operators: مقایسه‌ها و عملگرهای منطقی + comparisons: مقایسه‌ها + combining-expressions: ترکیب عبارات + coding-style-and-documentation: سبک کدنویسی و مستندسازی + python-style-guidelines-pep8: 'راهنمای سبک Python: PEP8' + docstrings: Docstring‌ها + exercises: تمرین‌ها +--- + +(python_done_right)= +```{raw} jupyter + +``` + +# اصول Python + +## مرور کلی + +ما حجم زیادی از مطالب را به سرعت پوشش داده‌ایم، با تمرکز بر مثال‌ها. + +اکنون بیایید برخی از ویژگی‌های اصلی Python را به شیوه‌ای منظم‌تر بررسی کنیم. + +این رویکرد هیجان‌انگیزتر نیست اما به روشن شدن برخی جزئیات کمک می‌کند. + +## انواع داده + +```{index} single: Python; Data Types +``` + +برنامه‌های کامپیوتری معمولاً طیف وسیعی از انواع داده را پیگیری می‌کنند. + +برای مثال، `1.5` یک عدد اعشاری است، در حالی که `1` یک عدد صحیح است. + +برنامه‌ها به دلایل مختلف نیاز به تمایز بین این دو نوع دارند. + +یکی از دلایل این است که آن‌ها به صورت متفاوتی در حافظه ذخیره می‌شوند. + +دلیل دیگر این است که عملیات حسابی متفاوت هستند + +* به عنوان مثال، محاسبات اعشاری در بیشتر ماشین‌ها توسط یک واحد اعشاری تخصصی (FPU) پیاده‌سازی می‌شود. + +به طور کلی، اعداد اعشاری اطلاعات بیشتری دارند اما عملیات حسابی روی اعداد صحیح سریع‌تر و دقیق‌تر است. + +Python انواع داده داخلی متعددی را فراهم می‌کند که برخی از آن‌ها را قبلاً دیده‌ایم + +* رشته‌ها، لیست‌ها، و غیره. + +بیایید کمی بیشتر درباره آن‌ها یاد بگیریم. + +### انواع داده ابتدایی + +(boolean)= +#### مقادیر Boolean + +یکی از انواع داده ساده، مقادیر **Boolean** است که می‌تواند `True` یا `False` باشد + +```{code-cell} python3 +x = True +x +``` + +می‌توانیم نوع هر شیء در حافظه را با استفاده از تابع `type()` بررسی کنیم. + +```{code-cell} python3 +type(x) +``` + +در خط بعدی کد، مفسر عبارت سمت راست = را ارزیابی می‌کند و y را به این مقدار متصل می‌کند + +```{code-cell} python3 +y = 100 < 10 +y +``` + +```{code-cell} python3 +type(y) +``` + +در عبارات حسابی، `True` به `1` و `False` به `0` تبدیل می‌شود. + +این به آن **محاسبات Boolean** گفته می‌شود و اغلب در برنامه‌نویسی مفید است. + +در اینجا چند مثال آورده شده است + +```{code-cell} python3 +x + y +``` + +```{code-cell} python3 +x * y +``` + +```{code-cell} python3 +True + True +``` + +```{code-cell} python3 +bools = [True, True, False, True] # List of Boolean values + +sum(bools) +``` + +#### انواع عددی + +انواع عددی نیز انواع داده ابتدایی مهمی هستند. + +ما قبلاً انواع `integer` و `float` را دیده‌ایم. + +**اعداد مختلط** یکی دیگر از انواع داده ابتدایی در Python هستند + +```{code-cell} python3 +x = complex(1, 2) +y = complex(2, 1) +print(x * y) + +type(x) +``` + +### ظروف + +Python چندین نوع اساسی برای ذخیره مجموعه‌هایی از داده‌های (احتمالاً ناهمگن) دارد. + +ما قبلاً {ref}`لیست‌ها را بحث کرده‌ایم `. + +```{index} single: Python; Tuples +``` + +یک نوع داده مرتبط، **tuple** است که لیست‌های "تغییرناپذیر" هستند + +```{code-cell} python3 +x = ('a', 'b') # Parentheses instead of the square brackets +x = 'a', 'b' # Or no brackets --- the meaning is identical +x +``` + +```{code-cell} python3 +type(x) +``` + +در Python، یک شیء **immutable** نامیده می‌شود اگر پس از ایجاد، نتوان آن را تغییر داد. + +برعکس، یک شیء **mutable** است اگر پس از ایجاد بتوان آن را تغییر داد. + +لیست‌های Python قابل تغییر هستند + +```{code-cell} python3 +x = [1, 2] +x[0] = 10 +x +``` + +اما tuple‌ها قابل تغییر نیستند + +```{code-cell} python3 +--- +tags: [raises-exception] +--- +x = (1, 2) +x[0] = 10 +``` + +کمی بعدتر درباره نقش داده‌های قابل تغییر و تغییرناپذیر بیشتر صحبت خواهیم کرد. + +tuple‌ها (و لیست‌ها) را می‌توان به صورت زیر "باز کرد" + +```{code-cell} python3 +integers = (10, 20, 30) +x, y, z = integers +x +``` + +```{code-cell} python3 +y +``` + +در واقع شما قبلاً {ref}`نمونه‌ای از این را دیده‌اید `. + +باز کردن tuple راحت است و ما اغلب از آن استفاده خواهیم کرد. + +#### نشانه‌گذاری Slice + +```{index} single: Python; Slicing +``` + +برای دسترسی به چندین عنصر از یک دنباله (یک لیست، یک tuple یا یک رشته)، می‌توانید از نشانه‌گذاری slice در Python استفاده کنید. + +برای مثال، + +```{code-cell} python3 +a = ["a", "b", "c", "d", "e"] +a[1:] +``` + +```{code-cell} python3 +a[1:3] +``` + +قانون کلی این است که `a[m:n]` تعداد `n - m` عنصر را بازمی‌گرداند، که از `a[m]` شروع می‌شود. + +اعداد منفی نیز مجاز هستند + +```{code-cell} python3 +a[-2:] # Last two elements of the list +``` + +همچنین می‌توانید از فرمت `[start:end:step]` برای مشخص کردن گام استفاده کنید + +```{code-cell} python3 +a[::2] +``` + +با استفاده از یک گام منفی، می‌توانید دنباله را به ترتیب معکوس برگردانید + +```{code-cell} python3 +a[-2::-1] # Walk backwards from the second last element to the first element +``` + +همان نشانه‌گذاری slice روی tuple‌ها و رشته‌ها کار می‌کند + +```{code-cell} python3 +s = 'foobar' +s[-3:] # Select the last three elements +``` + +#### Set‌ها و Dictionary‌ها + +```{index} single: Python; Sets +``` + +```{index} single: Python; Dictionaries +``` + +دو نوع ظرف دیگر که باید قبل از ادامه به آن‌ها اشاره کنیم [set‌ها](https://docs.python.org/3/tutorial/datastructures.html#sets) و [dictionary‌ها](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) هستند. + +dictionary‌ها بسیار شبیه لیست‌ها هستند، با این تفاوت که آیتم‌ها به جای شماره‌گذاری، نام‌گذاری می‌شوند + +```{code-cell} python3 +d = {'name': 'Frodo', 'age': 33} +type(d) +``` + +```{code-cell} python3 +d['age'] +``` + +نام‌های `'name'` و `'age'` *کلیدها* نامیده می‌شوند. + +اشیایی که کلیدها به آن‌ها نگاشت می‌شوند (`'Frodo'` و `33`) `مقادیر` نامیده می‌شوند. + +set‌ها مجموعه‌های بدون ترتیب و بدون تکرار هستند، و متدهای set عملیات معمول نظریه مجموعه‌ها را فراهم می‌کنند + +```{code-cell} python3 +s1 = {'a', 'b'} +type(s1) +``` + +```{code-cell} python3 +s2 = {'b', 'c'} +s1.issubset(s2) +``` + +```{code-cell} python3 +s1.intersection(s2) +``` + +تابع `set()` از دنباله‌ها set می‌سازد + +```{code-cell} python3 +s3 = set(('foo', 'bar', 'foo')) +s3 +``` + +## ورودی و خروجی + +```{index} single: Python; IO +``` + +بیایید به طور خلاصه خواندن و نوشتن در فایل‌های متنی را مرور کنیم، که با نوشتن شروع می‌شود + +```{code-cell} python3 +f = open('newfile.txt', 'w') # Open 'newfile.txt' for writing +f.write('Testing\n') # Here '\n' means new line +f.write('Testing again') +f.close() +``` + +در اینجا + +* تابع داخلی `open()` یک شیء فایل برای نوشتن ایجاد می‌کند. +* هر دو `write()` و `close()` متدهای اشیاء فایل هستند. + +این فایلی که ساخته‌ایم کجاست؟ + +به یاد داشته باشید که Python مفهوم دایرکتوری کاری فعلی (pwd) را حفظ می‌کند که می‌توان آن را از Jupyter یا IPython از طریق زیر یافت + +```{code-cell} ipython +%pwd +``` + +اگر مسیری مشخص نشود، Python در اینجا می‌نویسد. + +همچنین می‌توانیم از Python برای خواندن محتویات `newline.txt` به صورت زیر استفاده کنیم + +```{code-cell} python3 +f = open('newfile.txt', 'r') +out = f.read() +out +``` + +```{code-cell} python3 +print(out) +``` + +در واقع، رویکرد توصیه شده در Python مدرن استفاده از عبارت `with` است تا اطمینان حاصل شود که فایل‌ها به درستی دریافت و آزاد می‌شوند. + +محدود کردن عملیات در همان بلوک نیز وضوح کد شما را بهبود می‌بخشد. + +```{note} +این نوع بلوک به طور رسمی به عنوان یک [*context*](https://realpython.com/python-with-statement/#the-with-statement-approach) شناخته می‌شود. +``` + +بیایید سعی کنیم دو مثال بالا را به عبارت `with` تبدیل کنیم. + +ابتدا مثال نوشتن را تغییر می‌دهیم +```{code-cell} python3 + +with open('newfile.txt', 'w') as f: + f.write('Testing\n') + f.write('Testing again') +``` + +توجه کنید که نیازی به فراخوانی متد `close()` نداریم زیرا بلوک `with` اطمینان حاصل می‌کند که جریان در انتهای بلوک بسته می‌شود. + +با تغییرات جزئی، می‌توانیم فایل‌ها را با استفاده از `with` نیز بخوانیم + +```{code-cell} python3 +with open('newfile.txt', 'r') as fo: + out = fo.read() + print(out) +``` +اکنون فرض کنید که می‌خواهیم ورودی را از یک فایل بخوانیم و خروجی را در فایل دیگری بنویسیم. +در اینجا نحوه انجام این کار در حالی که به درستی منابع را دریافت و به سیستم عامل بازمی‌گردانیم با استفاده از عبارات `with` آمده است: + +```{code-cell} python3 +with open("newfile.txt", "r") as f: + file = f.readlines() + with open("output.txt", "w") as fo: + for i, line in enumerate(file): + fo.write(f'Line {i}: {line} \n') +``` + +فایل خروجی به صورت زیر خواهد بود + +```{code-cell} python3 +with open('output.txt', 'r') as fo: + print(fo.read()) +``` + +می‌توانیم مثال بالا را با گروه‌بندی دو عبارت `with` در یک خط ساده کنیم + +```{code-cell} python3 +with open("newfile.txt", "r") as f, open("output2.txt", "w") as fo: + for i, line in enumerate(f): + fo.write(f'Line {i}: {line} \n') +``` + +فایل خروجی یکسان خواهد بود + +```{code-cell} python3 +with open('output2.txt', 'r') as fo: + print(fo.read()) +``` + +فرض کنید می‌خواهیم به نوشتن در فایل موجود ادامه دهیم به جای بازنویسی آن. + +می‌توانیم حالت را به `a` تغییر دهیم که مخفف حالت append است + +```{code-cell} python3 +with open('output2.txt', 'a') as fo: + fo.write('\nThis is the end of the file') +``` + +```{code-cell} python3 +with open('output2.txt', 'r') as fo: + print(fo.read()) +``` + +```{note} +توجه کنید که ما فقط حالت‌های `r`، `w` و `a` را در اینجا پوشش دادیم که رایج‌ترین حالت‌ها هستند. +Python [حالت‌های متنوعی](https://www.geeksforgeeks.org/python/reading-writing-text-files-python/) ارائه می‌دهد که می‌توانید با آن‌ها آزمایش کنید. +``` + +### مسیرها + +```{index} single: Python; Paths +``` + +توجه کنید که اگر `newfile.txt` در دایرکتوری کاری فعلی نباشد، این فراخوانی `open()` شکست می‌خورد. + +در این حالت، می‌توانید فایل را به pwd منتقل کنید یا [مسیر کامل](https://en.wikipedia.org/wiki/Path_%28computing%29) فایل را مشخص کنید + +```{code-block} python3 +:class: no-execute + +f = open('insert_full_path_to_file/newfile.txt', 'r') +``` + +(iterating_version_1)= +## تکرار + +```{index} single: Python; Iteration +``` + +یکی از مهم‌ترین وظایف در محاسبات، گذر از یک دنباله از داده‌ها و انجام یک عمل مشخص است. + +یکی از نقاط قوت Python رابط ساده و انعطاف‌پذیر آن برای این نوع تکرار از طریق حلقه `for` است. + +### حلقه زدن روی اشیاء مختلف + +بسیاری از اشیاء Python "قابل تکرار" هستند، به این معنی که می‌توان روی آن‌ها حلقه زد. + +برای ارائه یک مثال، بیایید فایل us_cities.txt را بنویسیم که شهرهای ایالات متحده و جمعیت آن‌ها را فهرست می‌کند، در دایرکتوری کاری فعلی. + +(us_cities_data)= +```{code-cell} ipython +%%writefile us_cities.txt +new york: 8244910 +los angeles: 3819702 +chicago: 2707120 +houston: 2145146 +philadelphia: 1536471 +phoenix: 1469471 +san antonio: 1359758 +san diego: 1326179 +dallas: 1223229 +``` + +در اینجا `%%writefile` یک [IPython cell magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html#cell-magics) است. + +فرض کنید می‌خواهیم اطلاعات را خواناتر کنیم، با بزرگ کردن نام‌ها و اضافه کردن کاما برای نشان دادن هزارگان. + +برنامه زیر داده‌ها را می‌خواند و تبدیل را انجام می‌دهد: + +```{code-cell} python3 +data_file = open('us_cities.txt', 'r') +for line in data_file: + city, population = line.split(':') # Tuple unpacking + city = city.title() # Capitalize city names + population = f'{int(population):,}' # Add commas to numbers + print(city.ljust(15) + population) +data_file.close() +``` + +در اینجا `f'` یک f-string است [که برای درج متغیرها در رشته‌ها استفاده می‌شود](https://docs.python.org/3/library/string.html#formatspec). + +قالب‌بندی مجدد هر خط نتیجه سه متد مختلف رشته است که جزئیات آن‌ها را می‌توان برای بعد گذاشت. + +بخش جالب این برنامه برای ما خط 2 است که نشان می‌دهد + +1. شیء فایل `data_file` قابل تکرار است، به این معنی که می‌تواند در سمت راست `in` در یک حلقه `for` قرار گیرد. +1. تکرار از هر خط در فایل عبور می‌کند. + +این منجر به نحو تمیز و راحتی می‌شود که در برنامه ما نشان داده شده است. + +بسیاری از انواع دیگر اشیاء قابل تکرار هستند و ما بعداً درباره برخی از آن‌ها بحث خواهیم کرد. + +### حلقه زدن بدون ایندکس‌ها + +یکی از چیزهایی که ممکن است متوجه شده باشید این است که Python تمایل دارد حلقه زدن بدون ایندکس‌گذاری صریح را ترجیح دهد. + +برای مثال، + +```{code-cell} python3 +x_values = [1, 2, 3] # Some iterable x +for x in x_values: + print(x * x) +``` + +به این ترجیح داده می‌شود + +```{code-cell} python3 +for i in range(len(x_values)): + print(x_values[i] * x_values[i]) +``` + +وقتی این دو گزینه را مقایسه می‌کنید، می‌توانید ببینید چرا اولی ترجیح داده می‌شود. + +Python امکاناتی برای ساده‌سازی حلقه زدن بدون ایندکس فراهم می‌کند. + +یکی `zip()` است که برای گذر از جفت‌ها از دو دنباله استفاده می‌شود. + +برای مثال، کد زیر را اجرا کنید + +```{code-cell} python3 +countries = ('Japan', 'Korea', 'China') +cities = ('Tokyo', 'Seoul', 'Beijing') +for country, city in zip(countries, cities): + print(f'The capital of {country} is {city}') +``` + +تابع `zip()` همچنین برای ایجاد dictionary‌ها مفید است --- برای مثال + +```{code-cell} python3 +names = ['Tom', 'John'] +marks = ['E', 'F'] +dict(zip(names, marks)) +``` + +اگر واقعاً به ایندکس از یک لیست نیاز داریم، یکی از گزینه‌ها استفاده از `enumerate()` است. + +برای درک اینکه `enumerate()` چه کاری انجام می‌دهد، مثال زیر را در نظر بگیرید + +```{code-cell} python3 +letter_list = ['a', 'b', 'c'] +for index, letter in enumerate(letter_list): + print(f"letter_list[{index}] = '{letter}'") +``` +(list_comprehensions)= +### List Comprehension‌ها + +```{index} single: Python; List comprehension +``` + +همچنین می‌توانیم کد تولید لیست برداشت‌های تصادفی را با استفاده از چیزی به نام *list comprehension* به طور قابل توجهی ساده کنیم. + +[List comprehension‌ها](https://en.wikipedia.org/wiki/List_comprehension) یک ابزار زیبای Python برای ایجاد لیست هستند. + +مثال زیر را در نظر بگیرید، که list comprehension در سمت راست خط دوم است + +```{code-cell} python3 +animals = ['dog', 'cat', 'bird'] +plurals = [animal + 's' for animal in animals] +plurals +``` + +این یک مثال دیگر است + +```{code-cell} python3 +range(8) +``` + +```{code-cell} python3 +doubles = [2 * x for x in range(8)] +doubles +``` + +## مقایسه‌ها و عملگرهای منطقی + +### مقایسه‌ها + +```{index} single: Python; Comparison +``` + +بسیاری از انواع مختلف عبارات به یکی از مقادیر Boolean (یعنی `True` یا `False`) ارزیابی می‌شوند. + +یک نوع رایج، مقایسه‌ها هستند، مانند + +```{code-cell} python3 +x, y = 1, 2 +x < y +``` + +```{code-cell} python3 +x > y +``` + +یکی از ویژگی‌های خوب Python این است که می‌توانیم نامساوی‌ها را *زنجیره* کنیم + +```{code-cell} python3 +1 < 2 < 3 +``` + +```{code-cell} python3 +1 <= 2 <= 3 +``` + +همانطور که قبلاً دیدیم، هنگام آزمایش برابری از `==` استفاده می‌کنیم + +```{code-cell} python3 +x = 1 # Assignment +x == 2 # Comparison +``` + +برای "نابرابر" از `!=` استفاده کنید + +```{code-cell} python3 +1 != 2 +``` + +توجه کنید که هنگام آزمایش شرایط، می‌توانیم از **هر** عبارت معتبر Python استفاده کنیم + +```{code-cell} python3 +x = 'yes' if 42 else 'no' +x +``` + +```{code-cell} python3 +x = 'yes' if [] else 'no' +x +``` + +اینجا چه اتفاقی می‌افتد؟ + +قانون این است: + +* عباراتی که به صفر، دنباله‌ها یا ظروف خالی (رشته‌ها، لیست‌ها و غیره) و `None` ارزیابی می‌شوند، همه معادل `False` هستند. + * به عنوان مثال، `[]` و `()` در یک شرط `if` معادل `False` هستند +* همه مقادیر دیگر معادل `True` هستند. + * به عنوان مثال، `42` در یک شرط `if` معادل `True` است + +### ترکیب عبارات + +```{index} single: Python; Logical Expressions +``` + +می‌توانیم عبارات را با استفاده از `and`، `or` و `not` ترکیب کنیم. + +این‌ها ربط‌دهنده‌های منطقی استاندارد (عطف، فصل و نفی) هستند + +```{code-cell} python3 +1 < 2 and 'f' in 'foo' +``` + +```{code-cell} python3 +1 < 2 and 'g' in 'foo' +``` + +```{code-cell} python3 +1 < 2 or 'g' in 'foo' +``` + +```{code-cell} python3 +not True +``` + +```{code-cell} python3 +not not True +``` + +به خاطر بسپارید + +* `P and Q` زمانی `True` است که هر دو `True` باشند، در غیر این صورت `False` +* `P or Q` زمانی `False` است که هر دو `False` باشند، در غیر این صورت `True` + +همچنین می‌توانیم از `all()` و `any()` برای آزمایش دنباله‌ای از عبارات استفاده کنیم + +```{code-cell} python3 +all([1 <= 2 <= 3, 5 <= 6 <= 7]) +``` +```{code-cell} python3 +all([1 <= 2 <= 3, "a" in "letter"]) +``` +```{code-cell} python3 +any([1 <= 2 <= 3, "a" in "letter"]) +``` + +```{note} +* `all()` زمانی `True` برمی‌گرداند که *همه* مقادیر/عبارات boolean در دنباله `True` باشند +* `any()` زمانی `True` برمی‌گرداند که *هر* مقدار/عبارت boolean در دنباله `True` باشد +``` + +## سبک کدنویسی و مستندسازی + +سبک کدنویسی سازگار و استفاده از مستندسازی می‌تواند کد را راحت‌تر برای درک و نگهداری کند. + +### راهنمای سبک Python: PEP8 + +```{index} single: Python; PEP8 +``` + +می‌توانید فلسفه برنامه‌نویسی Python را با تایپ کردن `import this` در خط فرمان پیدا کنید. + +از جمله چیزهای دیگر، Python به شدت سازگاری در سبک برنامه‌نویسی را ترجیح می‌دهد. + +همه ما ضرب‌المثل درباره سازگاری و ذهن‌های کوچک را شنیده‌ایم. + +در برنامه‌نویسی، مانند ریاضیات، عکس آن درست است + +* یک مقاله ریاضی که در آن نمادهای $\cup$ و $\cap$ معکوس شده باشند، خواندن آن بسیار سخت خواهد بود، حتی اگر نویسنده در صفحه اول به شما بگوید. + +در Python، سبک استاندارد در [PEP8](https://peps.python.org/pep-0008/) بیان شده است. + +(گاهی اوقات در این سخنرانی‌ها از PEP8 منحرف خواهیم شد تا با نشانه‌گذاری ریاضی بهتر مطابقت داشته باشیم) + +(Docstrings)= +### Docstring‌ها + +```{index} single: Python; Docstrings +``` + +Python سیستمی برای اضافه کردن توضیحات به ماژول‌ها، کلاس‌ها، توابع و غیره دارد که *docstring* نامیده می‌شود. + +نکته خوب درباره docstring‌ها این است که در زمان اجرا در دسترس هستند. + +اجرای این کد را امتحان کنید + +```{code-cell} python3 +def f(x): + """ + This function squares its argument + """ + return x**2 +``` + +پس از اجرای این کد، docstring در دسترس است + +```{code-cell} ipython +f? +``` + +```{code-block} ipython +:class: no-execute + +Type: function +String Form: +File: /home/john/temp/temp.py +Definition: f(x) +Docstring: This function squares its argument +``` + +```{code-cell} ipython +f?? +``` + +```{code-block} ipython +:class: no-execute + +Type: function +String Form: +File: /home/john/temp/temp.py +Definition: f(x) +Source: +def f(x): + """ + This function squares its argument + """ + return x**2 +``` + +با یک علامت سوال docstring را می‌آوریم، و با دو علامت سوال کد منبع را نیز دریافت می‌کنیم. + +می‌توانید قراردادهای docstring را در [PEP257](https://peps.python.org/pep-0257/) پیدا کنید. + +## تمرین‌ها + +تمرین‌های زیر را حل کنید. + +(برای برخی، تابع داخلی `sum()` مفید است). + +```{exercise-start} +:label: pyess_ex1 +``` +قسمت 1: با توجه به دو لیست یا tuple عددی `x_vals` و `y_vals` با طول برابر، ضرب داخلی آن‌ها را با استفاده از `zip()` محاسبه کنید. + +قسمت 2: در یک خط، تعداد اعداد زوج در 0,...,99 را بشمارید. + +قسمت 3: با توجه به `pairs = ((2, 5), (4, 2), (9, 8), (12, 10))`، تعداد جفت‌های `(a, b)` را بشمارید که در آن هم `a` و هم `b` زوج باشند. + +```{hint} +:class: dropdown + +`x % 2` اگر `x` زوج باشد 0 برمی‌گرداند، در غیر این صورت 1. + +``` + +```{exercise-end} +``` + + +```{solution-start} pyess_ex1 +:class: dropdown +``` + +**راه‌حل قسمت 1:** + +یک راه‌حل ممکن اینجاست + +```{code-cell} python3 +x_vals = [1, 2, 3] +y_vals = [1, 1, 1] +sum([x * y for x, y in zip(x_vals, y_vals)]) +``` + +این هم کار می‌کند + +```{code-cell} python3 +sum(x * y for x, y in zip(x_vals, y_vals)) +``` + +**راه‌حل قسمت 2:** + +یک راه‌حل اینجاست + +```{code-cell} python3 +sum([x % 2 == 0 for x in range(100)]) +``` + +این هم کار می‌کند: + +```{code-cell} python3 +sum(x % 2 == 0 for x in range(100)) +``` + +برخی از جایگزین‌های کمتر طبیعی که با این حال به نشان دادن انعطاف‌پذیری list comprehension‌ها کمک می‌کنند عبارتند از + +```{code-cell} python3 +len([x for x in range(100) if x % 2 == 0]) +``` + +و + +```{code-cell} python3 +sum([1 for x in range(100) if x % 2 == 0]) +``` + +**راه‌حل قسمت 3:** + +یک احتمال اینجاست + +```{code-cell} python3 +pairs = ((2, 5), (4, 2), (9, 8), (12, 10)) +sum([x % 2 == 0 and y % 2 == 0 for x, y in pairs]) +``` + +```{solution-end} +``` + +```{exercise-start} +:label: pyess_ex2 +``` + +چندجمله‌ای زیر را در نظر بگیرید + +```{math} +:label: polynom0 + +p(x) += a_0 + a_1 x + a_2 x^2 + \cdots a_n x^n += \sum_{i=0}^n a_i x^i +``` + +تابعی `p` بنویسید به طوری که `p(x, coeff)` مقدار را در {eq}`polynom0` با توجه به نقطه `x` و لیست ضرایب `coeff` ($a_1, a_2, \cdots a_n$) محاسبه کند. + +سعی کنید از `enumerate()` در حلقه خود استفاده کنید. + +```{exercise-end} +``` + +```{solution-start} pyess_ex2 +:class: dropdown +``` +یک راه‌حل اینجاست: + +```{code-cell} python3 +def p(x, coeff): + return sum(a * x**i for i, a in enumerate(coeff)) +``` + +```{code-cell} python3 +p(1, (2, 4)) +``` + +```{solution-end} +``` + + +```{exercise-start} +:label: pyess_ex3 +``` + +تابعی بنویسید که یک رشته را به عنوان آرگومان می‌گیرد و تعداد حروف بزرگ در رشته را برمی‌گرداند. + +```{hint} +:class: dropdown + +`'foo'.upper()` مقدار `'FOO'` را برمی‌گرداند. + +``` + +```{exercise-end} +``` + +```{solution-start} pyess_ex3 +:class: dropdown +``` + +یک راه‌حل اینجاست: + +```{code-cell} python3 +def f(string): + count = 0 + for letter in string: + if letter == letter.upper() and letter.isalpha(): + count += 1 + return count + +f('The Rain in Spain') +``` + +یک جایگزین، راه‌حل pythonic‌تر: + +```{code-cell} python3 +def count_uppercase_chars(s): + return sum([c.isupper() for c in s]) + +count_uppercase_chars('The Rain in Spain') +``` + +```{solution-end} +``` + + + +```{exercise} +:label: pyess_ex4 + +تابعی بنویسید که دو دنباله `seq_a` و `seq_b` را به عنوان آرگومان می‌گیرد و `True` را برمی‌گرداند اگر هر عنصر در `seq_a` همچنین عنصری از `seq_b` باشد، در غیر این صورت `False`. + +* منظور از "دنباله" یک لیست، یک tuple یا یک رشته است. +* تمرین را بدون استفاده از [set‌ها](https://docs.python.org/3/tutorial/datastructures.html#sets) و متدهای set انجام دهید. +``` + +```{solution-start} pyess_ex4 +:class: dropdown +``` + +یک راه‌حل اینجاست: + +```{code-cell} python3 +def f(seq_a, seq_b): + for a in seq_a: + if a not in seq_b: + return False + return True + +# == test == # +print(f("ab", "cadb")) +print(f("ab", "cjdb")) +print(f([1, 2], [1, 2, 3])) +print(f([1, 2, 3], [1, 2])) +``` + +یک جایگزین، راه‌حل pythonic‌تر با استفاده از `all()`: + +```{code-cell} python3 +def f(seq_a, seq_b): + return all([i in seq_b for i in seq_a]) + +# == test == # +print(f("ab", "cadb")) +print(f("ab", "cjdb")) +print(f([1, 2], [1, 2, 3])) +print(f([1, 2, 3], [1, 2])) +``` + +البته، اگر از نوع داده `sets` استفاده کنیم، راه‌حل ساده‌تر است + +```{code-cell} python3 +def f(seq_a, seq_b): + return set(seq_a).issubset(set(seq_b)) +``` + +```{solution-end} +``` + + +```{exercise} +:label: pyess_ex5 + +وقتی کتابخانه‌های عددی را پوشش دهیم، خواهیم دید که آن‌ها شامل جایگزین‌های زیادی برای درونیابی و تقریب تابع هستند. + +با این حال، بیایید روتین تقریب تابع خودمان را به عنوان یک تمرین بنویسیم. + +به طور خاص، بدون استفاده از هیچ import، تابعی `linapprox` بنویسید که به عنوان آرگومان‌ها می‌گیرد + +* یک تابع `f` که بازه‌ای $[a, b]$ را به $\mathbb R$ نگاشت می‌کند. +* دو اسکالر `a` و `b` که حدود این بازه را مشخص می‌کنند. +* یک عدد صحیح `n` که تعداد نقاط شبکه را تعیین می‌کند. +* یک عدد `x` که `a <= x <= b` را برآورده می‌کند. + +و [درونیابی خطی تکه‌ای](https://en.wikipedia.org/wiki/Linear_interpolation) `f` را در `x`، بر اساس `n` نقطه شبکه با فاصله یکسان `a = point[0] < point[1] < ... < point[n-1] = b` برمی‌گرداند. + +برای وضوح تلاش کنید، نه کارایی. +``` + +```{solution-start} pyess_ex5 +:class: dropdown +``` +یک راه‌حل اینجاست: + +```{code-cell} python3 +def linapprox(f, a, b, n, x): + """ + Evaluates the piecewise linear interpolant of f at x on the interval + [a, b], with n evenly spaced grid points. + + Parameters + ========== + f : function + The function to approximate + + x, a, b : scalars (floats or integers) + Evaluation point and endpoints, with a <= x <= b + + n : integer + Number of grid points + + Returns + ======= + A float. The interpolant evaluated at x + + """ + length_of_interval = b - a + num_subintervals = n - 1 + step = length_of_interval / num_subintervals + + # === find first grid point larger than x === # + point = a + while point <= x: + point += step + + # === x must lie between the gridpoints (point - step) and point === # + u, v = point - step, point + + return f(u) + (x - u) * (f(v) - f(u)) / (v - u) +``` + +```{solution-end} +``` + + +```{exercise-start} +:label: pyess_ex6 +``` + +با استفاده از نحو list comprehension، می‌توانیم حلقه در کد زیر را ساده کنیم. + +```{code-cell} python3 +import numpy as np + +n = 100 +ϵ_values = [] +for i in range(n): + e = np.random.randn() + ϵ_values.append(e) +``` + +```{exercise-end} +``` + +```{solution-start} pyess_ex6 +:class: dropdown +``` + +یک راه‌حل اینجاست. + +```{code-cell} python3 +n = 100 +ϵ_values = [np.random.randn() for i in range(n)] +``` + +```{solution-end} +``` \ No newline at end of file From c026048a773d800ad658a05e1677511e0a41cdee Mon Sep 17 00:00:00 2001 From: Zahra-khanzadeh Date: Fri, 2 Jan 2026 15:59:03 +0330 Subject: [PATCH 4/7] Update lecture markdown files --- lectures/functions.md | 143 +++++++++++++++++------------------- lectures/getting_started.md | 16 ++-- 2 files changed, 77 insertions(+), 82 deletions(-) diff --git a/lectures/functions.md b/lectures/functions.md index 64d8ccf..b3fda59 100644 --- a/lectures/functions.md +++ b/lectures/functions.md @@ -23,18 +23,18 @@ kernelspec: ```{index} single: Python; User-defined functions ``` -## مرور کلی +## مقدمه -توابع (Functions) یکی از ساختارهای بسیار مفید هستند که تقریباً در تمام زبان‌های برنامه‌نویسی وجود دارند. +توابع (Functions) یکی از ساختارهای بسیار کاربردی هستند که تقریباً در تمام زبان‌های برنامه‌نویسی وجود دارند. ما تاکنون با چندین تابع آشنا شده‌ایم، مانند -* تابع `sqrt()` از کتابخانه NumPy و -* تابع داخلی `print()` +* تابع `()sqrt` از کتابخانه NumPy و +* تابع داخلی `()print` در این درس ما: -1. توابع را به صورت سیستماتیک بررسی می‌کنیم و نحوه نوشتن و موارد استفاده را پوشش می‌دهیم، و +1. توابع را به صورت سیستماتیک بررسی می‌کنیم و نحوه نوشتن و موارد استفاده از آنها را پوشش می‌دهیم، و 2. یاد می‌گیریم که چگونه توابع سفارشی خودمان را بسازیم. ما از import های زیر استفاده خواهیم کرد. @@ -44,15 +44,15 @@ import numpy as np import matplotlib.pyplot as plt ``` -## مبانی توابع +## اصول اولیه توابع تابع یک بخش نام‌گذاری شده از یک برنامه است که یک وظیفه خاص را اجرا می‌کند. -توابع زیادی از قبل وجود دارند و ما می‌توانیم از آنها به همین شکل استفاده کنیم. +توابع زیادی از قبل وجود دارند و ما می‌توانیم از آنها به همان شکل استفاده کنیم. ابتدا این توابع را بررسی می‌کنیم و سپس بحث می‌کنیم که چگونه می‌توانیم توابع خودمان را بسازیم. -### توابع داخلی +### توابع داخلی(Built-In) پایتون تعدادی تابع **داخلی** دارد که بدون نیاز به `import` در دسترس هستند. @@ -76,7 +76,7 @@ type(22) لیست کامل توابع داخلی پایتون در [اینجا](https://docs.python.org/3/library/functions.html) موجود است. -### توابع شخص ثالث +### توابع خارجی(Third Party) اگر توابع داخلی نیاز ما را پوشش ندهند، یا باید توابع را import کنیم یا توابع خودمان را بسازیم. @@ -91,7 +91,7 @@ calendar.isleap(2024) ## تعریف توابع -در بسیاری از موارد، توانایی تعریف توابع خودمان مفید است. +در بسیاری از موارد، باید بتوانیم توابع مدنظر خودمان را تعریف کنیم. بیایید با بحث در مورد نحوه انجام آن شروع کنیم. @@ -116,7 +116,7 @@ f(10) در اینجا یک تابع طولانی‌تر داریم که قدر مطلق یک عدد داده شده را محاسبه می‌کند. -(چنین تابعی قبلاً به عنوان یک تابع داخلی وجود دارد، اما بیایید برای تمرین، تابع خودمان را بنویسیم.) +(چنین تابعی از قبل به عنوان یک تابع داخلی وجود دارد، اما بیایید برای تمرین، تابع خودمان را بنویسیم.) ```{code-cell} python3 def new_abs_function(x): @@ -130,9 +130,9 @@ def new_abs_function(x): بیایید نحو را در اینجا بررسی کنیم. * `def` یک کلمه کلیدی پایتون است که برای شروع تعریف توابع استفاده می‌شود. -* `def new_abs_function(x):` نشان می‌دهد که نام تابع `new_abs_function` است و یک آرگومان واحد `x` دارد. +* `:def new_abs_function(x)` نشان می‌دهد که نام تابع `new_abs_function` است و یک آرگومان واحد `x` دارد. * کد تورفتگی‌دار یک بلوک کد است که *بدنه تابع* نامیده می‌شود. -* کلمه کلیدی `return` نشان می‌دهد که `abs_value` شیء‌ای است که باید به کد فراخوانی‌کننده برگردانده شود. +* کلمه کلیدی `return` نشان می‌دهد که `abs_value` شیئی است که باید به کد فراخوانی‌کننده برگردانده شود. تمام این تعریف تابع توسط مفسر پایتون خوانده می‌شود و در حافظه ذخیره می‌شود. @@ -145,7 +145,7 @@ print(new_abs_function(-3)) توجه کنید که یک تابع می‌تواند تعداد دلخواهی دستور `return` داشته باشد (از جمله صفر). -اجرای تابع زمانی که به اولین return برسد، خاتمه می‌یابد و این امکان را می‌دهد که کدهایی مانند مثال زیر بنویسیم +اجرای تابع زمانی که به اولین return برسد، خاتمه می‌یابد و این امکان را می‌دهد که کدهایی مانند مثال زیر بنویسیم: ```{code-cell} python3 def f(x): @@ -172,32 +172,32 @@ def f(x): plt.plot(x, 'b-', label="white noise") ``` -در این فراخوانی تابع `plot` کتابخانه Matplotlib، توجه کنید که آخرین آرگومان با نحو `name=argument` ارسال می‌شود. +در فراخوانی تابع `plot` از کتابخانه Matplotlib، باید توجه داشته باشید که آخرین آرگومان با نحو `name=argument` ارسال می‌شود. -این را یک *آرگومان کلیدواژه‌ای* می‌نامند، که `label` کلیدواژه است. +این را یک *آرگومان کلیدواژه‌ای(keyword argument)* می‌نامند، که `label` همان کلیدواژه است. -آرگومان‌های غیر کلیدواژه‌ای را *آرگومان‌های موضعی* می‌نامند، زیرا معنای آنها با ترتیب مشخص می‌شود +آرگومان‌های غیر کلیدواژه‌ای را *آرگومان‌های ترتیبی(positional argument)* می‌نامند، زیرا معنای آنها با ترتیب مشخص می‌شود. * `plot(x, 'b-')` با `plot('b-', x)` متفاوت است -آرگومان‌های کلیدواژه‌ای به ویژه زمانی مفید هستند که یک تابع آرگومان‌های زیادی دارد، در این صورت به خاطر سپردن ترتیب صحیح سخت است. +آرگومان‌های کلیدواژه‌ای زمانی کاربردی هستند که یک تابع آرگومان‌های زیادی دارد، در این صورت به خاطر سپردن ترتیب صحیح سخت است. شما می‌توانید آرگومان‌های کلیدواژه‌ای را در توابع تعریف شده توسط کاربر بدون مشکل به کار ببرید. -مثال بعدی نحو را نشان می‌دهد +به مثال بعدی توجه کنید: ```{code-cell} python3 def f(x, a=1, b=1): return a + b * x ``` -مقادیر آرگومان کلیدواژه‌ای که در تعریف `f` ارائه کردیم، به مقادیر پیش‌فرض تبدیل می‌شوند +مقادیر آرگومان کلیدواژه‌ای که در تعریف تابع `f` مشخص شده‌اند، به عنوان مقادیر پیش‌فرض درنظر گرفته می‌شوند ```{code-cell} python3 f(2) ``` -آنها را می‌توان به شکل زیر تغییر داد +آنها را می‌توان به شکل زیر تغییر داد: ```{code-cell} python3 f(2, a=4, b=5) @@ -209,13 +209,12 @@ f(2, a=4, b=5) به طور خاص -* هر تعداد تابع می‌تواند در یک فایل معین تعریف شود. -* توابع می‌توانند (و اغلب) در داخل توابع دیگر تعریف شوند. -* هر شیء می‌تواند به عنوان آرگومان به یک تابع ارسال شود، از جمله توابع دیگر. +* هر تعداد تابع می‌تواند در یک فایل مشخص تعریف شود. +* توابع می‌توانند (و اغلب هم می شوند) در داخل توابع دیگر تعریف شوند. +* هر شیء می‌تواند به عنوان آرگومان به یک تابع داده شود، از جمله توابع دیگر. * یک تابع می‌تواند هر نوع شیء را برگرداند، از جمله توابع. -ما در بخش‌های بعدی مثال‌هایی از اینکه چقدر ساده است که یک تابع را به یک تابع دیگر ارسال کنیم، ارائه خواهیم داد. - + در بخش‌های بعدی، با مثال‌هایی نشان خواهیم داد که انتقال یک تابع به یک تابع دیگر تا چه حد ساده است. ### توابع یک خطی: `lambda` ```{index} single: Python; lambda functions @@ -223,28 +222,24 @@ f(2, a=4, b=5) کلمه کلیدی `lambda` برای ایجاد توابع ساده در یک خط استفاده می‌شود. -به عنوان مثال، تعریف‌های زیر +برای نمونه، مثال های زیر کاملا معادل یکدیگر هستند: ```{code-cell} python3 def f(x): return x**3 ``` -و - ```{code-cell} python3 f = lambda x: x**3 ``` -کاملاً معادل هستند. - -برای اینکه ببینیم چرا `lambda` مفید است، فرض کنید می‌خواهیم $\int_0^2 x^3 dx$ را محاسبه کنیم (و حساب دبیرستانمان را فراموش کرده‌ایم). +برای اینکه ببینیم چرا `lambda` کاربردی است، فرض کنید می‌خواهیم $\int_0^2 x^3 dx$ را محاسبه کنیم (و حسابان دبیرستانمان را فراموش کرده‌ایم). کتابخانه SciPy تابعی به نام `quad` دارد که این محاسبه را برای ما انجام می‌دهد. نحو تابع `quad` به صورت `quad(f, a, b)` است که `f` یک تابع و `a` و `b` اعداد هستند. -برای ایجاد تابع $f(x) = x^3$ می‌توانیم از `lambda` به شکل زیر استفاده کنیم +برای ایجاد تابع $f(x) = x^3$ می‌توانیم از `lambda` به شکل زیر استفاده کنیم: ```{code-cell} python3 from scipy.integrate import quad @@ -252,16 +247,16 @@ from scipy.integrate import quad quad(lambda x: x**3, 0, 2) ``` -در اینجا تابع ایجاد شده توسط `lambda` *ناشناس* نامیده می‌شود زیرا هرگز نامی به آن داده نشده است. +در اینجا تابع ایجاد شده توسط `lambda` *ناشناس(anonymous)* نامیده می‌شود زیرا هرگز نامی به آن داده نشده است. -### چرا توابع بنویسیم؟ +### چرا تابع بنویسیم؟ -توابع تعریف شده توسط کاربر برای بهبود وضوح کد شما از طریق موارد زیر مهم هستند: +توابع تعریف شده توسط کاربر برای بهبود شفافیت و خوانایی کد شما اهمیت دارند، زیرا: -* جداسازی رشته‌های مختلف منطق -* تسهیل استفاده مجدد از کد +* جنبه‌های مختلف منطق برنامه را از هم جدا می‌کند +* امکان استفاده مجدد کد را فراهم می‌کنند -(نوشتن یک چیز دو بار [تقریباً همیشه ایده بدی است](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)) +(نوشتن یک چیز یکسان برای دو بار [تقریباً همیشه ایده بدی است](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)) ما بعداً بیشتر در این مورد صحبت خواهیم کرد. @@ -310,16 +305,16 @@ plt.show() وقتی مفسر به عبارت `generate_data(100)` می‌رسد، بدنه تابع را با `n` برابر با 100 اجرا می‌کند. -نتیجه خالص این است که نام `data` به لیست `ϵ_values` برگردانده شده توسط تابع *متصل* می‌شود. +نتیجه نهایی این است که نام `data` به لیست `ϵ_values` برگردانده شده توسط تابع *متصل* می‌شود. ### اضافه کردن شرط‌ها ```{index} single: Python; Conditions ``` -تابع `generate_data()` ما نسبتاً محدود است. +تابع `()generate_data` ما نسبتاً محدود است. -بیایید آن را با دادن قابلیت برگرداندن یا متغیرهای تصادفی نرمال استاندارد یا متغیرهای تصادفی یکنواخت در $(0, 1)$ بر اساس نیاز، کمی مفیدتر کنیم. +بیایید آن را با دادن قابلیت برگرداندن یا متغیرهای تصادفی نرمال استاندارد یا متغیرهای تصادفی یکنواخت در $(0, 1)$ بر اساس نیاز خودمان، کمی کاربردی‌تر کنیم. این کار در قطعه کد بعدی انجام می‌شود. @@ -340,18 +335,18 @@ plt.plot(data) plt.show() ``` -امیدواریم نحو عبارت if/else خود توضیح‌دهنده باشد، با تورفتگی که دوباره محدوده بلوک‌های کد را مشخص می‌کند. +امیدواریم نحو عبارت if/else خودش گویا باشد؛ در اینجا نیز همانند قبل، تورفتگی محدوده بلوک‌های کد را مشخص می‌کند. -نکات +نکات: -* ما آرگومان `U` را به عنوان یک رشته ارسال می‌کنیم، به همین دلیل آن را به صورت `'U'` می‌نویسیم. +* ما آرگومان `U` را به عنوان یک رشته بکار می‌بریم، به همین دلیل آن را به صورت `'U'` می‌نویسیم. * توجه کنید که برابری با نحو `==` آزمایش می‌شود، نه `=`. * به عنوان مثال، دستور `a = 10` نام `a` را به مقدار `10` اختصاص می‌دهد. - * عبارت `a == 10` به `True` یا `False` ارزیابی می‌شود، بسته به مقدار `a`. + * عبارت `a == 10` با توجه به مقدار`a` میتواند `True` یا `False` ارزیابی شود . حالا، چندین راه وجود دارد که می‌توانیم کد بالا را ساده کنیم. -به عنوان مثال، می‌توانیم شرط‌ها را کاملاً حذف کنیم و فقط نوع تولیدکننده مورد نظر را *به عنوان یک تابع* ارسال کنیم. +به عنوان مثال، می‌توانیم شرط‌ها را کاملاً حذف کنیم و فقط نوع خروجی مورد نظر را *به عنوان یک تابع* به برنامه بدهیم. برای درک این موضوع، نسخه زیر را در نظر بگیرید. @@ -369,7 +364,7 @@ plt.plot(data) plt.show() ``` -حالا، وقتی تابع `generate_data()` را فراخوانی می‌کنیم، `np.random.uniform` را به عنوان آرگومان دوم ارسال می‌کنیم. +حالا، وقتی تابع `()generate_data` را فراخوانی می‌کنیم، `np.random.uniform` را به عنوان آرگومان دوم ارسال می‌کنیم. این شیء یک *تابع* است. @@ -377,7 +372,7 @@ plt.show() * در حالی که این خطوط اجرا می‌شوند، نام‌های `generator_type` و `np.random.uniform` "مترادف" هستند و می‌توانند به روش‌های یکسان استفاده شوند. -این اصل به طور کلی‌تر کار می‌کند---به عنوان مثال، قطعه کد زیر را در نظر بگیرید +این اصل به طور کلی هم کار می‌کند؛ به عنوان مثال، قطعه کد زیر را در نظر بگیرید: ```{code-cell} python3 max(7, 2, 4) # max() is a built-in Python function @@ -388,23 +383,23 @@ m = max m(7, 2, 4) ``` -در اینجا ما نام دیگری برای تابع داخلی `max()` ایجاد کردیم که سپس می‌توانست به روش‌های یکسان استفاده شود. +در اینجا ما نام دیگری برای تابع داخلی `()max` ایجاد کردیم که سپس می‌توانست به روش‌های یکسان استفاده شود. -در زمینه برنامه ما، توانایی اتصال نام‌های جدید به توابع به این معنی است که هیچ مشکلی در *ارسال یک تابع به عنوان آرگومان به تابع دیگر* وجود ندارد---همانطور که در بالا انجام دادیم. +در چارچوب برنامه ما، توانایی اتصال نام‌های جدید به توابع به این معنی است که هیچ مشکلی در *ارسال یک تابع به عنوان آرگومان به تابع دیگر* وجود ندارد؛همانطور که در بالا انجام دادیم. (recursive_functions)= -## فراخوانی‌های بازگشتی تابع (پیشرفته) +## فراخوانی‌ توابع بازگشتی (پیشرفته) ```{index} single: Python; Recursion ``` -این یک موضوع پیشرفته است که می‌توانید آن را رد کنید. +این یک مبحث پیشرفته است که می‌توانید از مطالعه آن صرفنظر کنید. -در عین حال، این ایده جالبی است که باید در مرحله‌ای از حرفه برنامه‌نویسی خود آن را یاد بگیرید. +با این حال، ایده‌ی جالبی است که در مراحل بعدی برنامه‌نویسی خود با آن آشنا شوید. -اساساً، یک تابع بازگشتی تابعی است که خودش را فراخوانی می‌کند. +اساساً، یک تابع بازگشتی(Recursive Function) تابعی است که خودش را فراخوانی می‌کند. -به عنوان مثال، مسئله محاسبه $x_t$ برای برخی از t را در نظر بگیرید که +به عنوان مثال، مسئله محاسبه $x_t$ برای برخی از مقادیر t را در نظر بگیرید که ```{math} :label: xseqdoub @@ -424,7 +419,7 @@ def x_loop(t): return x ``` -همچنین می‌توانیم از یک راه‌حل بازگشتی استفاده کنیم، به شرح زیر +همچنین می‌توانیم از یک راه‌حل بازگشتی همانند زیر استفاده کنیم: ```{code-cell} python3 def x(t): @@ -434,13 +429,13 @@ def x(t): return 2 * x(t-1) ``` -آنچه در اینجا اتفاق می‌افتد این است که هر فراخوانی متوالی از *فریم* خود در *پشته* استفاده می‌کند +آنچه در اینجا اتفاق می‌افتد این است که هر فراخوانی متوالی، فریم(frame) مخصوص خودش را در پشته(stack) استفاده می‌کند. -* فریم جایی است که متغیرهای محلی یک فراخوانی تابع معین نگهداری می‌شود +* فریم جایی است که متغیرهای محلی یک فراخوانی تابع مشخص نگهداری می‌شود * پشته حافظه‌ای است که برای پردازش فراخوانی‌های تابع استفاده می‌شود - * یک صف First In Last Out (FILO) + * و مانند یک صف ورود اول، خروج آخر یا First In Last Out (FILO) عمل می کند. -این مثال تا حدودی ساختگی است، زیرا اولین راه‌حل (تکراری) معمولاً به راه‌حل بازگشتی ترجیح داده می‌شود. +این مثال تا حدودی ساختگی است، زیرا معمولا راه‌حل تکراری(iterative) معمولاً به جای راه‌حل بازگشتی(recursive) ترجیح داده می‌شود. ما بعداً با کاربردهای کمتر ساختگی بازگشت آشنا خواهیم شد. @@ -467,7 +462,7 @@ $n! = n \times (n - 1) \times \cdots \times 2 \times 1$ تعریف می‌شود :class: dropdown ``` -در اینجا یک راه‌حل است: +یک راه حل این است: ```{code-cell} python3 def factorial(n): @@ -503,7 +498,7 @@ factorial(4) :class: dropdown ``` -در اینجا یک راه‌حل است: +یک راه حل این است: ```{code-cell} python3 from numpy.random import uniform @@ -526,15 +521,15 @@ binomial_rv(10, 0.5) :label: func_ex3 ``` -اولاً، تابعی بنویسید که یک تحقق از دستگاه تصادفی زیر را برگرداند +ابتدا، تابعی بنویسید که یک نمونه از دستگاه تصادفی زیر را برگرداند: -1. یک سکه بی‌طرفانه را 10 بار پرتاب کنید. -1. اگر شیر `k` بار یا بیشتر به طور متوالی در این دنباله حداقل یک بار رخ دهد، یک دلار پرداخت کنید. +1. یک سکه را عادلانه 10 بار پرتاب کنید. +1. اگر شیر `k` بار یا بیشتر به طور متوالی در این دنباله حداقل یک بار ظاهر شود، یک دلار پرداخت کنید. 1. در غیر این صورت، چیزی پرداخت نکنید. -ثانیاً، تابع دیگری بنویسید که همان کار را انجام دهد به جز اینکه قانون دوم دستگاه تصادفی بالا به این شکل تبدیل شود +سپس، تابع دیگری بنویسید که همان کار را انجام دهد به جز اینکه قانون دوم دستگاه تصادفی بالا به این شکل تبدیل :شود -- اگر شیر `k` بار یا بیشتر در این دنباله رخ دهد، یک دلار پرداخت کنید. +- اگر شیر `k` بار یا بیشتر در این دنباله ظاهر شود، یک دلار پرداخت کنید. از هیچ import به جز `from numpy.random import uniform` استفاده نکنید. @@ -545,7 +540,7 @@ binomial_rv(10, 0.5) :class: dropdown ``` -در اینجا تابعی برای دستگاه تصادفی اول است. +در اینجا تابعی برای دستگاه تصادفی اول آورده شده است: ```{code-cell} python3 from numpy.random import uniform @@ -567,7 +562,7 @@ def draw(k): # pays if k consecutive successes in a sequence draw(3) ``` -در اینجا تابع دیگری برای دستگاه تصادفی دوم است. +در اینجا تابع دیگری برای دستگاه تصادفی دوم وجود دارد: ```{code-cell} python3 def draw_new(k): # pays if k successes in a sequence @@ -592,7 +587,7 @@ draw_new(3) ## تمرینات پیشرفته -در تمرینات زیر، ما با هم توابع بازگشتی خواهیم نوشت. +در تمرینات زیر، ما با هم توابع بازگشتی را خواهیم نوشت. ```{exercise-start} :label: func_ex4 @@ -617,7 +612,7 @@ x_{t+1} = x_t + x_{t-1}, \quad x_0 = 0, \; x_1 = 1 :class: dropdown ``` -در اینجا راه‌حل استاندارد است +در اینجا راه‌حل استاندارد این مسئله را می توانید ببینید: ```{code-cell} python3 def x(t): @@ -642,7 +637,7 @@ print([x(i) for i in range(10)]) :label: func_ex5 ``` -تابع `factorial()` از [تمرین 1](factorial_exercise) را با استفاده از بازگشت بازنویسی کنید. +تابع `()factorial` از [تمرین 1](factorial_exercise) را با استفاده از بازگشت بازنویسی کنید. ```{exercise-end} ``` @@ -651,7 +646,7 @@ print([x(i) for i in range(10)]) :class: dropdown ``` -در اینجا راه‌حل استاندارد است +در اینجا راه‌حل استاندارد را میتوانید ببینید: ```{code-cell} python3 def recursion_factorial(n): diff --git a/lectures/getting_started.md b/lectures/getting_started.md index 85a7794..6ecc345 100644 --- a/lectures/getting_started.md +++ b/lectures/getting_started.md @@ -42,7 +42,7 @@ kernelspec: ساده ترین راه برای شروع کدنویسی در پایتون، اجرای آن در فضای ابری است. ( یعنی با استفاده از یک سرور از راه دور که از قبل روی آن پایتون نصب شده است.) یکی دیگر از گزینه های رایگان و قابل اعتماد نیز [Google Colab](https://colab.research.google.com/) است. علاوه براین Colab دارای مزیت GPU نیز هست که ما از آن در دوره های پیشرفته تر استفاده خواهیم کرد. آموزش نحوه ی استفاده از Google Colab را می توانید در اینترنت جستجو کنید و ویدیوهای مربوط به آن را پیدا کنید. -بیشتر دوره های ما شامل یک دکمه «راه اندازی نوت بوک» (با یک آیکون پخش) در بالای سمت راست هستند که شما را به یک نسخه قابل اجرا در Colab متصل می کند. +بیشتر دوره های ما یک دکمه «راه اندازی نوت بوک» (با یک آیکون پخش) در بالای صفحه سمت چپ دارد که شما را به یک نسخه قابل اجرا در Colab متصل می کند. ## نصب محلی اگر به سیستم مناسب دسترسی دارید و قصد دارید حجم قابل توجهی برنامه نویسی با پایتون انجام دهید، نصب محلی انتخاب بهتری است. این روش به شما امکان کنترل و انعطاف پذیری بیشتری در استفاده از ابزارها را می دهد. @@ -411,7 +411,7 @@ debugger breakpoint ```{index} single: Jupyter Notebook; nbviewer ``` -فایل های نوت بوک صرفا فایل های متنی با ساختار [JSON](https://en.wikipedia.org/wiki/JSON) هستند که معمولا پسوند `.ipynb` دارند. +فایل های نوت بوک صرفا فایل های متنی با ساختار [JSON](https://en.wikipedia.org/wiki/JSON) هستند که معمولا پسوند `ipynb.` دارند. شما می توانید آن ها را به همان شیوه که سایر فایل ها را به اشتراک می گذارید، ارسال کنید یا اینکه از سرویس های وب مانند [nbviewer](http://nbviewer.jupyter.org/) استفاده کنید. @@ -485,7 +485,7 @@ conda upgrade quantecon ``` ## کار با فایل های پایتون -تا اینجا بیشتر روی اجرای کدهای پایتون در سلول های ژوپیتر نوت بوک تمرکز کردیم. اما به صورت سنتی، بیشتر کدهای پایتون به شکل دیگری اجرا می شوند. به این شکل که ابتدا کدها در یک فایل متنی روی سیستم ذخیره می شوند که به طور قراردادی دارای پسوند `.py` هستند. +تا اینجا بیشتر روی اجرای کدهای پایتون در سلول های ژوپیتر نوت بوک تمرکز کردیم. اما به صورت سنتی، بیشتر کدهای پایتون به شکل دیگری اجرا می شوند. به این شکل که ابتدا کدها در یک فایل متنی روی سیستم ذخیره می شوند که به طور قراردادی دارای پسوند `py.` هستند. برای نمونه می توانیم یک نوع از این فایل ایجاد کنیم: @@ -497,11 +497,11 @@ print("foobar") دستور بالا خط `print("foobar")` را در فایلی به نام `foo.py` در مسیر فعلی ذخیره می کند. -در این کد دستور `%%writefile` نمونه ای از یک جادوی سلولی ([cell magic](http://ipython.readthedocs.org/en/stable/interactive/magics.html#cell-magics)) است! +در این کد دستور `writefile%%` نمونه ای از یک جادوی سلولی ([cell magic](http://ipython.readthedocs.org/en/stable/interactive/magics.html#cell-magics)) است! ### ویرایش و اجرا -اگر با کدی مواجه شدید که در یک فایل با پسوند `*.py` ذخیره شده است، لازم است به این دو سوال توجه کنید: +اگر با کدی مواجه شدید که در یک فایل با پسوند `py.*` ذخیره شده است، لازم است به این دو سوال توجه کنید: 1. چگونه باید آن را اجرا کرد؟ @@ -514,7 +514,7 @@ print("foobar") ```{index} single: JupyterLab ``` -محیط [JupyterLab](https://github.com/jupyterlab/jupyterlab) یک محیط توسعه ی یکپارچه (IDE) است که بر پایه ی نوت بوک ها ژوپیتر ساخته شده است. با استفاده از JupyterLab می توانید فایل هایی با پسوند `*.py` را همانند ژوپیتر نوت بوک ها را ویرایش و اجرا کنید. +محیط [JupyterLab](https://github.com/jupyterlab/jupyterlab) یک محیط توسعه ی یکپارچه (IDE) است که بر پایه ی نوت بوک ها ژوپیتر ساخته شده است. با استفاده از JupyterLab می توانید فایل هایی با پسوند `py.*` را همانند ژوپیتر نوت بوک ها را ویرایش و اجرا کنید. برای اجرای JupyterLab می توانید آن را در فهرست برنامه ها جستجو کنید یا در ترمینال دستور `jupyter-lab` را وارد نمایید. @@ -528,7 +528,7 @@ print("foobar") به طور کلی، ویرایشگر متن برنامه ای است که به طور اختصاصی برای کار با فایل های متنی مانند برنامه های پایتون طراحی شده است. -البته هیچ چیز قدرت و کارایی یک ویرایشگر متن خوب را برای کار با کدهای برنامه نویسی را ندارد. +البته هیچ چیز قدرت و کارایی یک ویرایشگر متن خوب را برای کار با کدهای برنامه نویسی ندارد. یک ویرایشگر خوب امکانات زیر را ارائه می دهد: @@ -551,7 +551,7 @@ print("foobar") حالا دوباره ژوپیتر را این بار با استفاده از کد دستوری `jupyter notebook --no-browser` باز کنید. -با این کار، هسته ی ژوپیتز (kernel) بدون آنکه مرورگر به صورت خودکار باز شود، راه اندازی می شود. +با این کار، هسته ی ژوپیتر (kernel) بدون آنکه مرورگر به صورت خودکار باز شود، راه اندازی می شود. همچنین به پیامی که هنگام شروع نمایش داده می شود دقت کنید: باید یک آدرس(URL) مانند `http://localhost:8888` به شما بدهد که نوت بوک در آن درحال اجرا است. From 3a578e7c02e4552ab574b53a888e960e4ce7acb6 Mon Sep 17 00:00:00 2001 From: Zahra-khanzadeh Date: Sat, 3 Jan 2026 12:45:10 +0330 Subject: [PATCH 5/7] Update Python-essentials lecture content and TOC --- lectures/_toc.yml | 2 +- lectures/python_essentials.md | 329 +++++++++++++++++----------------- 2 files changed, 163 insertions(+), 168 deletions(-) diff --git a/lectures/_toc.yml b/lectures/_toc.yml index 524b302..ef44aad 100644 --- a/lectures/_toc.yml +++ b/lectures/_toc.yml @@ -8,7 +8,7 @@ parts: - file: getting_started - file: python_by_example - file: functions - # - file: python_essentials + - file: python_essentials # - file: oop_intro # - file: names # - file: python_oop diff --git a/lectures/python_essentials.md b/lectures/python_essentials.md index fe7cfc2..9708581 100644 --- a/lectures/python_essentials.md +++ b/lectures/python_essentials.md @@ -8,26 +8,26 @@ kernelspec: language: python name: python3 heading-map: - overview: مرور کلی + overview: مقدمه data-types: انواع داده primitive-data-types: انواع داده ابتدایی boolean-values: مقادیر Boolean - numeric-types: انواع عددی - containers: ظروف + numeric-types: انواع داده عددی + containers: ظرف ها slice-notation: نشانه‌گذاری Slice - sets-and-dictionaries: Set‌ها و Dictionary‌ها + sets-and-dictionaries: مجموعه‌ها و دیکشنری ها input-and-output: ورودی و خروجی paths: مسیرها iterating: تکرار - looping-over-different-objects: حلقه زدن روی اشیاء مختلف - looping-without-indices: حلقه زدن بدون ایندکس‌ها - list-comprehensions: List Comprehension‌ها - comparisons-and-logical-operators: مقایسه‌ها و عملگرهای منطقی - comparisons: مقایسه‌ها + looping-over-different-objects: حلقه تکرار اشیاء مختلف + looping-without-indices: حلقه تکرار بدون ایندکس‌ها + list-comprehensions: خلاصه لیست‌ها + comparisons-and-logical-operators: عملگرهای مقایسه‌ای و منطقی + comparisons: عملگرهای مقایسه‌ای combining-expressions: ترکیب عبارات coding-style-and-documentation: سبک کدنویسی و مستندسازی - python-style-guidelines-pep8: 'راهنمای سبک Python: PEP8' - docstrings: Docstring‌ها + python-style-guidelines-pep8: راهنمای سبک کدنویسی پایتون: PEP8 + docstrings: داک‌استرینگ‌ها (docstring) exercises: تمرین‌ها --- @@ -40,60 +40,53 @@ heading-map: ``` -# اصول Python +# اصول برنامه‌نویسی پایتون -## مرور کلی +## مقدمه -ما حجم زیادی از مطالب را به سرعت پوشش داده‌ایم، با تمرکز بر مثال‌ها. +ما تاکنون مطالب زیادی را با تمرکز بر مثال‌ها، به‌سرعت پوشش داده‌ایم. -اکنون بیایید برخی از ویژگی‌های اصلی Python را به شیوه‌ای منظم‌تر بررسی کنیم. +اکنون بیایید برخی ویژگی‌های اصلی پایتون را به‌صورت نظام‌مندتر بررسی کنیم. -این رویکرد هیجان‌انگیزتر نیست اما به روشن شدن برخی جزئیات کمک می‌کند. +این روش شاید کمتر هیجان‌انگیز باشد، اما به درک بهتر جزئیات کمک می‌کند. ## انواع داده ```{index} single: Python; Data Types ``` -برنامه‌های کامپیوتری معمولاً طیف وسیعی از انواع داده را پیگیری می‌کنند. +برنامه‌های کامپیوتری مجموعه‌ای از انواع داده را مدیریت می‌کنند. +برای مثال، `1.5` یک عدد اعشاری (float) است، در حالی که `1` یک عدد صحیح (integer) محسوب می‌شود. در برنامه نویسی باید بین این دو نوع تفاوت قائل شوید، زیرا در حافظه به شکل متفاوتی ذخیره می‌شوند و عملیات ریاضی روی آنها فرق دارد. -برای مثال، `1.5` یک عدد اعشاری است، در حالی که `1` یک عدد صحیح است. + * به عنوان نمونه، در بیشتر رایانه‌ها محاسبات اعشاری توسط یک واحد خاص به نام **واحد ممیز شناور (FPU)** انجام می‌شود. -برنامه‌ها به دلایل مختلف نیاز به تمایز بین این دو نوع دارند. -یکی از دلایل این است که آن‌ها به صورت متفاوتی در حافظه ذخیره می‌شوند. +به طور کلی، اعداد اعشاری اطلاعات بیشتری دارند اما عملیات ریاضی روی اعداد صحیح سریع‌تر و دقیق‌تر است. -دلیل دیگر این است که عملیات حسابی متفاوت هستند -* به عنوان مثال، محاسبات اعشاری در بیشتر ماشین‌ها توسط یک واحد اعشاری تخصصی (FPU) پیاده‌سازی می‌شود. + * پایتون چندین نوع دادهٔ داخلی دیگر نیز دارد، مثل رشته‌ها (strings) و فهرست‌ها (lists). -به طور کلی، اعداد اعشاری اطلاعات بیشتری دارند اما عملیات حسابی روی اعداد صحیح سریع‌تر و دقیق‌تر است. +بیایید بیشتر با آن‌ها آشنا شویم. -Python انواع داده داخلی متعددی را فراهم می‌کند که برخی از آن‌ها را قبلاً دیده‌ایم - -* رشته‌ها، لیست‌ها، و غیره. - -بیایید کمی بیشتر درباره آن‌ها یاد بگیریم. - -### انواع داده ابتدایی +### انواع داده اولیه (Primitive Data Types) (boolean)= -#### مقادیر Boolean +#### مقادیر بولی (Boolean) -یکی از انواع داده ساده، مقادیر **Boolean** است که می‌تواند `True` یا `False` باشد +یک نوع از داده های اولیه، مقادیر **بولی** هستند که می‌توانند فقط `True` (درست) یا `False` (نادرست) باشند. ```{code-cell} python3 x = True x ``` -می‌توانیم نوع هر شیء در حافظه را با استفاده از تابع `type()` بررسی کنیم. +می‌توانیم نوع هر شیء در حافظه را با استفاده از تابع `()type` بررسی کنیم: ```{code-cell} python3 type(x) ``` -در خط بعدی کد، مفسر عبارت سمت راست = را ارزیابی می‌کند و y را به این مقدار متصل می‌کند +مثلاً در مثال زیر، پایتون مقدار عبارت سمت راست را محاسبه کرده و آن را به متغیر `y` نسبت می‌دهد: ```{code-cell} python3 y = 100 < 10 @@ -104,11 +97,11 @@ y type(y) ``` -در عبارات حسابی، `True` به `1` و `False` به `0` تبدیل می‌شود. +در عبارات ریاضی، `True` معادل `1` و `False` معادل `0` در نظر گرفته می‌شود. -این به آن **محاسبات Boolean** گفته می‌شود و اغلب در برنامه‌نویسی مفید است. +این ویژگی را **محاسبات بولی (Boolean arithmetic)** می‌نامند و اغلب در برنامه نویسی کاربردی است. -در اینجا چند مثال آورده شده است +مثال های زیر نمونه هایی از این دست هستند: ```{code-cell} python3 x + y @@ -128,13 +121,13 @@ bools = [True, True, False, True] # List of Boolean values sum(bools) ``` -#### انواع عددی +#### انواع داده‌های عددی -انواع عددی نیز انواع داده ابتدایی مهمی هستند. +داده های عددی از دیگر داده‌های اولیه هستند. -ما قبلاً انواع `integer` و `float` را دیده‌ایم. +همانطور که پیشتر با داده های صحیح (integer) و اعشاری (float) یا به اختصار `int`و `float` آشنا شدید؛ نوعی دیگر از داده های عددی **اعداد مختلط (complex)** نام دارند. -**اعداد مختلط** یکی دیگر از انواع داده ابتدایی در Python هستند +همانند مثال زیر: ```{code-cell} python3 x = complex(1, 2) @@ -144,16 +137,17 @@ print(x * y) type(x) ``` -### ظروف +### ظرف ها یا ساختارهای نگه دارنده(Containers) + +پایتون چندین نوع پایه برای ذخیره سازی مجموعه هایی از داده ها(احتمالا ناهمگن) دارد. -Python چندین نوع اساسی برای ذخیره مجموعه‌هایی از داده‌های (احتمالاً ناهمگن) دارد. -ما قبلاً {ref}`لیست‌ها را بحث کرده‌ایم `. +پییش‌تر با {ref}`لیست‌ها ` آشنا شدیم. ```{index} single: Python; Tuples ``` -یک نوع داده مرتبط، **tuple** است که لیست‌های "تغییرناپذیر" هستند +نوعی دیگر از آن، **تاپل (tuple)** است که «غیرقابل تغییر» (immutable) می باشد. ```{code-cell} python3 x = ('a', 'b') # Parentheses instead of the square brackets @@ -165,11 +159,10 @@ x type(x) ``` -در Python، یک شیء **immutable** نامیده می‌شود اگر پس از ایجاد، نتوان آن را تغییر داد. +اگر شیئی پس از ساخته شدن قابل تغییر نباشد، **immutable** است. +در مقابل، اگر قابل ویرایش باشد، **mutable** نام دارد. -برعکس، یک شیء **mutable** است اگر پس از ایجاد بتوان آن را تغییر داد. - -لیست‌های Python قابل تغییر هستند +در پایتون لیست ها قابل تغییر هستند: ```{code-cell} python3 x = [1, 2] @@ -177,7 +170,7 @@ x[0] = 10 x ``` -اما tuple‌ها قابل تغییر نیستند +اما tuple‌ها قابل تغییر نیستند: ```{code-cell} python3 --- @@ -189,7 +182,7 @@ x[0] = 10 کمی بعدتر درباره نقش داده‌های قابل تغییر و تغییرناپذیر بیشتر صحبت خواهیم کرد. -tuple‌ها (و لیست‌ها) را می‌توان به صورت زیر "باز کرد" +می‌توان تاپل‌ها (و لیست‌ها) را به صورت زیر «بازکرد» (unpack) کرد: ```{code-cell} python3 integers = (10, 20, 30) @@ -205,14 +198,13 @@ y باز کردن tuple راحت است و ما اغلب از آن استفاده خواهیم کرد. -#### نشانه‌گذاری Slice - +#### نشانه گذاری برش (Slice Notation) ```{index} single: Python; Slicing ``` -برای دسترسی به چندین عنصر از یک دنباله (یک لیست، یک tuple یا یک رشته)، می‌توانید از نشانه‌گذاری slice در Python استفاده کنید. +برای دسترسی به چندین عنصر از یک دنباله (یک لیست، یک tuple یا یک رشته)، می‌توانید از نشانه‌گذاری slice در پایتون استفاده کنید. -برای مثال، +برای مثال: ```{code-cell} python3 a = ["a", "b", "c", "d", "e"] @@ -225,32 +217,32 @@ a[1:3] قانون کلی این است که `a[m:n]` تعداد `n - m` عنصر را بازمی‌گرداند، که از `a[m]` شروع می‌شود. -اعداد منفی نیز مجاز هستند +اعداد منفی نیز مجاز هستند: ```{code-cell} python3 a[-2:] # Last two elements of the list ``` -همچنین می‌توانید از فرمت `[start:end:step]` برای مشخص کردن گام استفاده کنید +همچنین می‌توانید از قالب `[start:end:step]` برای مشخص کردن گام برش استفاده کنید: ```{code-cell} python3 a[::2] ``` -با استفاده از یک گام منفی، می‌توانید دنباله را به ترتیب معکوس برگردانید +با استفاده از یک گام منفی، می‌توانید دنباله را به صورت معکوس برگردانید: ```{code-cell} python3 a[-2::-1] # Walk backwards from the second last element to the first element ``` -همان نشانه‌گذاری slice روی tuple‌ها و رشته‌ها کار می‌کند +همان نشانه‌گذاری slice روی tuple‌ها و رشته‌ها نیز کار می‌کند: ```{code-cell} python3 s = 'foobar' s[-3:] # Select the last three elements ``` -#### Set‌ها و Dictionary‌ها +#### مجموعه‌ها و دیکشنری‌ها (Sets and Dictionaries) ```{index} single: Python; Sets ``` @@ -258,9 +250,9 @@ s[-3:] # Select the last three elements ```{index} single: Python; Dictionaries ``` -دو نوع ظرف دیگر که باید قبل از ادامه به آن‌ها اشاره کنیم [set‌ها](https://docs.python.org/3/tutorial/datastructures.html#sets) و [dictionary‌ها](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) هستند. +دو نوع دیگر از ظرف ها در پایتون،[مجموعه ها (sets)](https://docs.python.org/3/tutorial/datastructures.html#sets) و [دیکشنری ها (dictionaries)](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) هستند. -dictionary‌ها بسیار شبیه لیست‌ها هستند، با این تفاوت که آیتم‌ها به جای شماره‌گذاری، نام‌گذاری می‌شوند +دیکشنری‌ها بسیار شبیه لیست‌ها هستند، با این تفاوت که آیتم‌ها به جای شماره‌گذاری، نام‌گذاری می‌شوند: ```{code-cell} python3 d = {'name': 'Frodo', 'age': 33} @@ -271,11 +263,11 @@ type(d) d['age'] ``` -نام‌های `'name'` و `'age'` *کلیدها* نامیده می‌شوند. +در این مثال از دیکشنری، نام های `'name'` و`'age'` *کلیدها(keys)* نامیده می‌شوند. -اشیایی که کلیدها به آن‌ها نگاشت می‌شوند (`'Frodo'` و `33`) `مقادیر` نامیده می‌شوند. +اشیایی که کلیدها به آن‌ها ارجاع می‌دهند (`'Frodo'` و `33`) `مقادیر(Values)` نامیده می‌شوند. -set‌ها مجموعه‌های بدون ترتیب و بدون تکرار هستند، و متدهای set عملیات معمول نظریه مجموعه‌ها را فراهم می‌کنند +**مجموعه‌ها(sets)** دسته های بدون ترتیب و بدون عنصر تکراری هستند و متدهای مجموعه،عملیات معمول مربوط به مجموعه ها را فراهم می کنند: ```{code-cell} python3 s1 = {'a', 'b'} @@ -291,19 +283,21 @@ s1.issubset(s2) s1.intersection(s2) ``` -تابع `set()` از دنباله‌ها set می‌سازد +تابع `()set` مجموعه ها را از دنباله ها می سازد: ```{code-cell} python3 s3 = set(('foo', 'bar', 'foo')) s3 ``` -## ورودی و خروجی +## ورودی و خروجی (Input and Output) ```{index} single: Python; IO ``` -بیایید به طور خلاصه خواندن و نوشتن در فایل‌های متنی را مرور کنیم، که با نوشتن شروع می‌شود +بیایید به طور خلاصه خواندن و نوشتن در فایل‌های متنی را مرور کنیم. + +با نوشتن شروع می‌کنیم: ```{code-cell} python3 f = open('newfile.txt', 'w') # Open 'newfile.txt' for writing @@ -312,22 +306,23 @@ f.write('Testing again') f.close() ``` -در اینجا +در اینجا: -* تابع داخلی `open()` یک شیء فایل برای نوشتن ایجاد می‌کند. -* هر دو `write()` و `close()` متدهای اشیاء فایل هستند. +* تابع سازنده داخلی `()open`یک فایل برای نوشتن ایجاد می کند. +* هم `()write` و هم `()close` متدهای فایل های ایجادشده هستند. این فایلی که ساخته‌ایم کجاست؟ -به یاد داشته باشید که Python مفهوم دایرکتوری کاری فعلی (pwd) را حفظ می‌کند که می‌توان آن را از Jupyter یا IPython از طریق زیر یافت +به خاطر داشته باشید که پایتون مفهوم دایرکتوری فعلی (present working directory یا pwd) شما را حفظ می کند، که در Jupyter یا IPython می توان آن را از طریق دستور زیر پیدا کرد: + ```{code-cell} ipython %pwd ``` -اگر مسیری مشخص نشود، Python در اینجا می‌نویسد. +اگر مسیری مشخص نشده باشد، پایتون در همین مکان(پوشه جاری)فایل را می نویسد. -همچنین می‌توانیم از Python برای خواندن محتویات `newline.txt` به صورت زیر استفاده کنیم +ما همچنین میتوانیم با پایتون محتوای فایل `newline.txt` را به صورت زیر بخوانیم: ```{code-cell} python3 f = open('newfile.txt', 'r') @@ -339,7 +334,7 @@ out print(out) ``` -در واقع، رویکرد توصیه شده در Python مدرن استفاده از عبارت `with` است تا اطمینان حاصل شود که فایل‌ها به درستی دریافت و آزاد می‌شوند. +در واقع، رویکرد پیشنهادی در پایتون مدرن، استفاده از یک دستور `with` است تا اطمینان حاصل شود که فایل‌ها به درستی دریافت و منتشر می‌شوند. محدود کردن عملیات در همان بلوک نیز وضوح کد شما را بهبود می‌بخشد. @@ -349,7 +344,7 @@ print(out) بیایید سعی کنیم دو مثال بالا را به عبارت `with` تبدیل کنیم. -ابتدا مثال نوشتن را تغییر می‌دهیم +ابتدا مثال نوشتن را تغییر می‌دهیم: ```{code-cell} python3 with open('newfile.txt', 'w') as f: @@ -357,9 +352,9 @@ with open('newfile.txt', 'w') as f: f.write('Testing again') ``` -توجه کنید که نیازی به فراخوانی متد `close()` نداریم زیرا بلوک `with` اطمینان حاصل می‌کند که جریان در انتهای بلوک بسته می‌شود. +توجه کنید که نیازی به فراخوانی متد `()close` نداریم زیرا بلوک `with` تضمین می‌کند که جریان(stream) در پایان بلوک بسته شود. -با تغییرات جزئی، می‌توانیم فایل‌ها را با استفاده از `with` نیز بخوانیم +با کمی تغییر، می‌توانیم فایل‌ها را با استفاده از دستور `with` نیز بخوانیم: ```{code-cell} python3 with open('newfile.txt', 'r') as fo: @@ -377,14 +372,14 @@ with open("newfile.txt", "r") as f: fo.write(f'Line {i}: {line} \n') ``` -فایل خروجی به صورت زیر خواهد بود +فایل خروجی به صورت زیر خواهد بود: ```{code-cell} python3 with open('output.txt', 'r') as fo: print(fo.read()) ``` -می‌توانیم مثال بالا را با گروه‌بندی دو عبارت `with` در یک خط ساده کنیم +می‌توانیم مثال بالا را ساده کنیم با این کار که دو دستور `with` را در یک خط قرار دهیم: ```{code-cell} python3 with open("newfile.txt", "r") as f, open("output2.txt", "w") as fo: @@ -392,16 +387,16 @@ with open("newfile.txt", "r") as f, open("output2.txt", "w") as fo: fo.write(f'Line {i}: {line} \n') ``` -فایل خروجی یکسان خواهد بود +فایل خروجی یکسان خواهد بود: ```{code-cell} python3 with open('output2.txt', 'r') as fo: print(fo.read()) ``` -فرض کنید می‌خواهیم به نوشتن در فایل موجود ادامه دهیم به جای بازنویسی آن. +فرض کنید می‌خواهیم به جای بازنویسی فایل موجود به نوشتن در آن ادامه دهیم. -می‌توانیم حالت را به `a` تغییر دهیم که مخفف حالت append است +می‌توانیم حالت را به `a` تغییر دهیم که مخفف حالت append است: ```{code-cell} python3 with open('output2.txt', 'a') as fo: @@ -414,18 +409,18 @@ with open('output2.txt', 'r') as fo: ``` ```{note} -توجه کنید که ما فقط حالت‌های `r`، `w` و `a` را در اینجا پوشش دادیم که رایج‌ترین حالت‌ها هستند. -Python [حالت‌های متنوعی](https://www.geeksforgeeks.org/python/reading-writing-text-files-python/) ارائه می‌دهد که می‌توانید با آن‌ها آزمایش کنید. +توجه کنید که ما فقط حالت‌های `r`، `w` و `a` را در اینجا پوشش دادیم که رایج‌ترین حالت‌های مورد استفاده هستند. +پایتون [حالت‌های متنوعی](https://www.geeksforgeeks.org/python/reading-writing-text-files-python/) ارائه می‌دهد که می‌توانید با آن‌ها آزمایش کنید. ``` -### مسیرها +### مسیرها (Paths) ```{index} single: Python; Paths ``` -توجه کنید که اگر `newfile.txt` در دایرکتوری کاری فعلی نباشد، این فراخوانی `open()` شکست می‌خورد. +توجه کنید که اگر `newfile.txt` در دایرکتوری کاری فعلی نباشد، فراخوانی `()open` با خطا مواجه می‌شود. -در این حالت، می‌توانید فایل را به pwd منتقل کنید یا [مسیر کامل](https://en.wikipedia.org/wiki/Path_%28computing%29) فایل را مشخص کنید +در این حالت، می‌توانید فایل را به pwd منتقل کنید یا [مسیر کامل](https://en.wikipedia.org/wiki/Path_%28computing%29) فایل را مشخص کنید: ```{code-block} python3 :class: no-execute @@ -434,20 +429,20 @@ f = open('insert_full_path_to_file/newfile.txt', 'r') ``` (iterating_version_1)= -## تکرار +## تکرار(Iteration) ```{index} single: Python; Iteration ``` -یکی از مهم‌ترین وظایف در محاسبات، گذر از یک دنباله از داده‌ها و انجام یک عمل مشخص است. +یکی از مهم‌ترین وظایف در علوم کامپیوتر، عبور گام‌به‌گام از یک دنباله از داده‌ها و انجام یک عمل مشخص است. -یکی از نقاط قوت Python رابط ساده و انعطاف‌پذیر آن برای این نوع تکرار از طریق حلقه `for` است. +یکی از نقاط قوت پایتون رابط کاربری ساده و انعطاف‌پذیر آن برای این نوع تکرار از طریق حلقه `for` است. -### حلقه زدن روی اشیاء مختلف +### حلقه تکرار روی اشیاء مختلف -بسیاری از اشیاء Python "قابل تکرار" هستند، به این معنی که می‌توان روی آن‌ها حلقه زد. +بسیاری از اشیاء پایتون "قابل تکرار" هستند، به این معنی که می‌توان روی آن‌ها حلقه(loop) زد. -برای ارائه یک مثال، بیایید فایل us_cities.txt را بنویسیم که شهرهای ایالات متحده و جمعیت آن‌ها را فهرست می‌کند، در دایرکتوری کاری فعلی. +برای ارائه یک مثال، بیایید فایل us_cities.txt را بنویسیم که شهرهای ایالات متحده و جمعیت آن‌ها را فهرست می‌کندو در پوشه کاری فعلی ذخیره می گردد: (us_cities_data)= ```{code-cell} ipython @@ -463,9 +458,9 @@ san diego: 1326179 dallas: 1223229 ``` -در اینجا `%%writefile` یک [IPython cell magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html#cell-magics) است. +در اینجا `writefile%%` یک [IPython cell magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html#cell-magics) است. -فرض کنید می‌خواهیم اطلاعات را خواناتر کنیم، با بزرگ کردن نام‌ها و اضافه کردن کاما برای نشان دادن هزارگان. +فرض کنید می‌خواهیم اطلاعات را با بزرگ کردن نام‌ها و اضافه کردن ویرگول برای نشان دادن هزارگان خواناتر کنیم. برنامه زیر داده‌ها را می‌خواند و تبدیل را انجام می‌دهد: @@ -479,24 +474,24 @@ for line in data_file: data_file.close() ``` -در اینجا `f'` یک f-string است [که برای درج متغیرها در رشته‌ها استفاده می‌شود](https://docs.python.org/3/library/string.html#formatspec). +در اینجا `'f` یک f-string است [که برای درج متغیرها در رشته‌ها استفاده می‌شود](https://docs.python.org/3/library/string.html#formatspec). -قالب‌بندی مجدد هر خط نتیجه سه متد مختلف رشته است که جزئیات آن‌ها را می‌توان برای بعد گذاشت. +قالب‌بندی مجدد هر خط نتیجه سه متد مختلف رشته است که بررسی جزئیات آن‌ها را می‌توان برای بعد گذاشت. -بخش جالب این برنامه برای ما خط 2 است که نشان می‌دهد +بخش جالب این برنامه برای ما خط 2 است که نشان می‌دهد: -1. شیء فایل `data_file` قابل تکرار است، به این معنی که می‌تواند در سمت راست `in` در یک حلقه `for` قرار گیرد. -1. تکرار از هر خط در فایل عبور می‌کند. +1. شیء فایل `data_file` قابل تکرار است، به این معنی که می‌توان آن را در سمت راست `in` در یک حلقه `for` قرار داد. +1. تکرار به صورت خط به خط از فایل عبور می‌کند. -این منجر به نحو تمیز و راحتی می‌شود که در برنامه ما نشان داده شده است. +این همان چیزی است که منجر به سینتکس ساده و کاربردی نمایش داده شده در برنامه ما می شود. بسیاری از انواع دیگر اشیاء قابل تکرار هستند و ما بعداً درباره برخی از آن‌ها بحث خواهیم کرد. -### حلقه زدن بدون ایندکس‌ها +### حلقه تکرار بدون ایندکس‌ها -یکی از چیزهایی که ممکن است متوجه شده باشید این است که Python تمایل دارد حلقه زدن بدون ایندکس‌گذاری صریح را ترجیح دهد. +یکی از چیزهایی که ممکن است متوجه شده باشید این است که پایتون تمایل دارد مستقیما روی آیتم ها حلقه بزنیم، بدون اینکه شماره موقعیت(یا همان ایندکس) هر آیتم را به صورت صریح استفاده کنیم. -برای مثال، +برای مثال: ```{code-cell} python3 x_values = [1, 2, 3] # Some iterable x @@ -504,7 +499,7 @@ for x in x_values: print(x * x) ``` -به این ترجیح داده می‌شود +به این ترجیح داده می‌شود: ```{code-cell} python3 for i in range(len(x_values)): @@ -513,11 +508,11 @@ for i in range(len(x_values)): وقتی این دو گزینه را مقایسه می‌کنید، می‌توانید ببینید چرا اولی ترجیح داده می‌شود. -Python امکاناتی برای ساده‌سازی حلقه زدن بدون ایندکس فراهم می‌کند. +پایتون امکاناتی دارد که کار با حلقه ها را بدون ایندکس ساده می‌کند. -یکی `zip()` است که برای گذر از جفت‌ها از دو دنباله استفاده می‌شود. +یکی از این امکانات `()zip` است که به شما اجازه می‌دهد دو لیست را هم زمان با هم طی کنید و هر بار یک جفت از عناصر آنها را بگیرید. -برای مثال، کد زیر را اجرا کنید +برای مثال، کد زیر را اجرا کنید: ```{code-cell} python3 countries = ('Japan', 'Korea', 'China') @@ -526,7 +521,7 @@ for country, city in zip(countries, cities): print(f'The capital of {country} is {city}') ``` -تابع `zip()` همچنین برای ایجاد dictionary‌ها مفید است --- برای مثال +تابع `()zip` همچنین برای ایجاد دیکشنری‌ها کاربردی است، برای مثال: ```{code-cell} python3 names = ['Tom', 'John'] @@ -534,9 +529,9 @@ marks = ['E', 'F'] dict(zip(names, marks)) ``` -اگر واقعاً به ایندکس از یک لیست نیاز داریم، یکی از گزینه‌ها استفاده از `enumerate()` است. +اگر واقعاً به شماره موقعیت یا ایندکس از یک لیست نیاز داریم، یکی از گزینه‌ها استفاده از `()enumerate` است. -برای درک اینکه `enumerate()` چه کاری انجام می‌دهد، مثال زیر را در نظر بگیرید +برای درک اینکه `()enumerate` چه کاری انجام می‌دهد، مثال زیر را در نظر بگیرید: ```{code-cell} python3 letter_list = ['a', 'b', 'c'] @@ -544,16 +539,16 @@ for index, letter in enumerate(letter_list): print(f"letter_list[{index}] = '{letter}'") ``` (list_comprehensions)= -### List Comprehension‌ها +### ‌خلاصه لیست (List Comprehension) ```{index} single: Python; List comprehension ``` -همچنین می‌توانیم کد تولید لیست برداشت‌های تصادفی را با استفاده از چیزی به نام *list comprehension* به طور قابل توجهی ساده کنیم. +همچنین می‌توانیم کد تولید لیست مقادیر تصادفی را با استفاده از چیزی به نام *خلاصه لیست(list comprehension)* به طور قابل توجهی ساده کنیم. -[List comprehension‌ها](https://en.wikipedia.org/wiki/List_comprehension) یک ابزار زیبای Python برای ایجاد لیست هستند. +[خلاصه لیست‌ها](https://en.wikipedia.org/wiki/List_comprehension) یک ابزار زیبای پایتون برای ایجاد لیست هستند. -مثال زیر را در نظر بگیرید، که list comprehension در سمت راست خط دوم است +مثال زیر را در نظر بگیرید، که خلاصه لیست در سمت راست خط دوم است: ```{code-cell} python3 animals = ['dog', 'cat', 'bird'] @@ -561,7 +556,7 @@ plurals = [animal + 's' for animal in animals] plurals ``` -این یک مثال دیگر است +این یک مثال دیگر است: ```{code-cell} python3 range(8) @@ -572,16 +567,16 @@ doubles = [2 * x for x in range(8)] doubles ``` -## مقایسه‌ها و عملگرهای منطقی +## عملگرهای مقایسه‌ای و منطقی -### مقایسه‌ها +### عملگرهای مقایسه‌ای ```{index} single: Python; Comparison ``` -بسیاری از انواع مختلف عبارات به یکی از مقادیر Boolean (یعنی `True` یا `False`) ارزیابی می‌شوند. +بسیاری از انواع مختلف عبارات وجود دارند که نتیجه‌شان با یکی از مقادیر Boolean (یعنی `True` یا `False`) نشان داده می‌شوند. -یک نوع رایج، مقایسه‌ها هستند، مانند +یکی از رایج ترین این عبارت ها، عملگرهای مقایسه‌ای هستند، مانند: ```{code-cell} python3 x, y = 1, 2 @@ -592,7 +587,7 @@ x < y x > y ``` -یکی از ویژگی‌های خوب Python این است که می‌توانیم نامساوی‌ها را *زنجیره* کنیم +یکی از ویژگی‌های خوب پایتون این است که می‌توان نامساوی‌ها را به صورت *پشت سر هم (Chain)* در یک عبارت نوشت. ```{code-cell} python3 1 < 2 < 3 @@ -602,20 +597,20 @@ x > y 1 <= 2 <= 3 ``` -همانطور که قبلاً دیدیم، هنگام آزمایش برابری از `==` استفاده می‌کنیم +همانطور که قبلاً دیدیم، هنگام آزمایش برابری از `==` استفاده می‌کنیم: ```{code-cell} python3 x = 1 # Assignment x == 2 # Comparison ``` -برای "نابرابر" از `!=` استفاده کنید +برای "نابرابر" از `!=` استفاده کنید: ```{code-cell} python3 1 != 2 ``` -توجه کنید که هنگام آزمایش شرایط، می‌توانیم از **هر** عبارت معتبر Python استفاده کنیم +توجه کنید که هنگام آزمایش شرایط، می‌توانیم از **هر** عبارت معتبر پایتون استفاده کنیم: ```{code-cell} python3 x = 'yes' if 42 else 'no' @@ -631,7 +626,7 @@ x قانون این است: -* عباراتی که به صفر، دنباله‌ها یا ظروف خالی (رشته‌ها، لیست‌ها و غیره) و `None` ارزیابی می‌شوند، همه معادل `False` هستند. +* عباراتی که به صفر، دنباله‌ها یا ظرف های خالی (رشته‌ها، لیست‌ها و غیره) و `None` تشخیص داده می‌شوند، همه معادل `False` هستند. * به عنوان مثال، `[]` و `()` در یک شرط `if` معادل `False` هستند * همه مقادیر دیگر معادل `True` هستند. * به عنوان مثال، `42` در یک شرط `if` معادل `True` است @@ -643,7 +638,7 @@ x می‌توانیم عبارات را با استفاده از `and`، `or` و `not` ترکیب کنیم. -این‌ها ربط‌دهنده‌های منطقی استاندارد (عطف، فصل و نفی) هستند +این‌ها ربط‌دهنده‌های منطقی استاندارد (عطف، فصل و نفی) هستند. ```{code-cell} python3 1 < 2 and 'f' in 'foo' @@ -665,12 +660,12 @@ not True not not True ``` -به خاطر بسپارید +به خاطر بسپارید: * `P and Q` زمانی `True` است که هر دو `True` باشند، در غیر این صورت `False` * `P or Q` زمانی `False` است که هر دو `False` باشند، در غیر این صورت `True` -همچنین می‌توانیم از `all()` و `any()` برای آزمایش دنباله‌ای از عبارات استفاده کنیم +همچنین می‌توانیم از `()all` و `()any` برای آزمایش دنباله‌ای از عبارات استفاده کنیم: ```{code-cell} python3 all([1 <= 2 <= 3, 5 <= 6 <= 7]) @@ -683,44 +678,44 @@ any([1 <= 2 <= 3, "a" in "letter"]) ``` ```{note} -* `all()` زمانی `True` برمی‌گرداند که *همه* مقادیر/عبارات boolean در دنباله `True` باشند -* `any()` زمانی `True` برمی‌گرداند که *هر* مقدار/عبارت boolean در دنباله `True` باشد +* `()all` زمانی `True` برمی‌گرداند که *همه* مقادیر/عبارات boolean در دنباله `True` باشند +* `()any` زمانی `True` برمی‌گرداند که *هر* مقدار/عبارت boolean در دنباله `True` باشد ``` ## سبک کدنویسی و مستندسازی -سبک کدنویسی سازگار و استفاده از مستندسازی می‌تواند کد را راحت‌تر برای درک و نگهداری کند. +داشتن یک سبک کدنویسی سازگار و استفاده از مستندسازی می‌تواند کد را خواناتر و نگهداری و توسعه آن را آسان تر کند. -### راهنمای سبک Python: PEP8 +### راهنمای سبک کدنویسی پایتون: PEP8 ```{index} single: Python; PEP8 ``` -می‌توانید فلسفه برنامه‌نویسی Python را با تایپ کردن `import this` در خط فرمان پیدا کنید. +می‌توانید با تایپ کردن `import this` در خط فرمان با فلسفه برنامه‌نویسی پایتون آشنا شوید. -از جمله چیزهای دیگر، Python به شدت سازگاری در سبک برنامه‌نویسی را ترجیح می‌دهد. +پایتون در کنار موارد دیگر، تأکید زیادی بر یکدست بودن و ثبات در سبک برنامه نویسی دارد. -همه ما ضرب‌المثل درباره سازگاری و ذهن‌های کوچک را شنیده‌ایم. +همه ما ضرب‌المثل « سازگاری و ذهن‌های کوچک » را شنیده‌ایم. -در برنامه‌نویسی، مانند ریاضیات، عکس آن درست است +در برنامه‌نویسی، همانند ریاضیات، کاملا برعکس است. * یک مقاله ریاضی که در آن نمادهای $\cup$ و $\cap$ معکوس شده باشند، خواندن آن بسیار سخت خواهد بود، حتی اگر نویسنده در صفحه اول به شما بگوید. -در Python، سبک استاندارد در [PEP8](https://peps.python.org/pep-0008/) بیان شده است. +در پایتون، سبک استاندارد در [PEP8](https://peps.python.org/pep-0008/) بیان شده است. -(گاهی اوقات در این سخنرانی‌ها از PEP8 منحرف خواهیم شد تا با نشانه‌گذاری ریاضی بهتر مطابقت داشته باشیم) +(گاهی اوقات در این درس ها از PEP8 منحرف خواهیم شد تا نمادگذاری ریاضی را بهتر رعایت کنیم) (Docstrings)= -### Docstring‌ها +### داک‌استرینگ‌ها (docstring) ```{index} single: Python; Docstrings ``` -Python سیستمی برای اضافه کردن توضیحات به ماژول‌ها، کلاس‌ها، توابع و غیره دارد که *docstring* نامیده می‌شود. +پایتون سیستمی برای اضافه کردن توضیحات به ماژول‌ها، کلاس‌ها، توابع و غیره دارد که *داک‌استرینگ‌(docstring)* نامیده می‌شود. -نکته خوب درباره docstring‌ها این است که در زمان اجرا در دسترس هستند. +نکته خوب درباره داک‌استرینگ‌‌ها این است که در زمان اجرا در دسترس هستند. -اجرای این کد را امتحان کنید +اجرای این کد را امتحان کنید: ```{code-cell} python3 def f(x): @@ -730,7 +725,7 @@ def f(x): return x**2 ``` -پس از اجرای این کد، docstring در دسترس است +پس از اجرای این کد، داک‌استرینگ‌ در دسترس است: ```{code-cell} ipython f? @@ -765,22 +760,22 @@ def f(x): return x**2 ``` -با یک علامت سوال docstring را می‌آوریم، و با دو علامت سوال کد منبع را نیز دریافت می‌کنیم. +با یک علامت سوال داک‌استرینگ‌ را می‌آوریم، و با دو علامت سوال کد منبع را نیز دریافت می‌کنیم. -می‌توانید قراردادهای docstring را در [PEP257](https://peps.python.org/pep-0257/) پیدا کنید. +می‌توانید قراردادهای داک‌استرینگ‌ را در [PEP257](https://peps.python.org/pep-0257/) پیدا کنید. ## تمرین‌ها تمرین‌های زیر را حل کنید. -(برای برخی، تابع داخلی `sum()` مفید است). +(برای برخی از تمرینات، تابع داخلی `()sum` کاربردی است). ```{exercise-start} :label: pyess_ex1 ``` -قسمت 1: با توجه به دو لیست یا tuple عددی `x_vals` و `y_vals` با طول برابر، ضرب داخلی آن‌ها را با استفاده از `zip()` محاسبه کنید. +قسمت 1: با توجه به دو لیست یا tuple عددی `x_vals` و `y_vals` با طول برابر، ضرب داخلی آن‌ها را با استفاده از `()zip` محاسبه کنید. -قسمت 2: در یک خط، تعداد اعداد زوج در 0,...,99 را بشمارید. +قسمت 2: در یک خط، تعداد اعداد زوج در بازه 0,...,99 را بشمارید. قسمت 3: با توجه به `pairs = ((2, 5), (4, 2), (9, 8), (12, 10))`، تعداد جفت‌های `(a, b)` را بشمارید که در آن هم `a` و هم `b` زوج باشند. @@ -801,7 +796,7 @@ def f(x): **راه‌حل قسمت 1:** -یک راه‌حل ممکن اینجاست +یک راه‌حل ممکن میتواند این باشد: ```{code-cell} python3 x_vals = [1, 2, 3] @@ -809,7 +804,7 @@ y_vals = [1, 1, 1] sum([x * y for x, y in zip(x_vals, y_vals)]) ``` -این هم کار می‌کند +این روش هم برای این سوال کار می‌کند: ```{code-cell} python3 sum(x * y for x, y in zip(x_vals, y_vals)) @@ -817,19 +812,19 @@ sum(x * y for x, y in zip(x_vals, y_vals)) **راه‌حل قسمت 2:** -یک راه‌حل اینجاست +یک راه‌حل ممکن میتواند این باشد: ```{code-cell} python3 sum([x % 2 == 0 for x in range(100)]) ``` -این هم کار می‌کند: +این روش هم برای این سوال کار می‌کند: ```{code-cell} python3 sum(x % 2 == 0 for x in range(100)) ``` -برخی از جایگزین‌های کمتر طبیعی که با این حال به نشان دادن انعطاف‌پذیری list comprehension‌ها کمک می‌کنند عبارتند از +برخی از جایگزین‌های کمتر طبیعی که با این حال به نشان دادن انعطاف‌پذیری خلاصه لیست‌ها کمک می‌کنند عبارتند از: ```{code-cell} python3 len([x for x in range(100) if x % 2 == 0]) @@ -843,7 +838,7 @@ sum([1 for x in range(100) if x % 2 == 0]) **راه‌حل قسمت 3:** -یک احتمال اینجاست +یک راه حل این است: ```{code-cell} python3 pairs = ((2, 5), (4, 2), (9, 8), (12, 10)) @@ -857,7 +852,7 @@ sum([x % 2 == 0 and y % 2 == 0 for x, y in pairs]) :label: pyess_ex2 ``` -چندجمله‌ای زیر را در نظر بگیرید +چندجمله‌ای زیر را در نظر بگیرید: ```{math} :label: polynom0 @@ -867,9 +862,9 @@ p(x) = \sum_{i=0}^n a_i x^i ``` -تابعی `p` بنویسید به طوری که `p(x, coeff)` مقدار را در {eq}`polynom0` با توجه به نقطه `x` و لیست ضرایب `coeff` ($a_1, a_2, \cdots a_n$) محاسبه کند. +تابع `p` را بنویسید به طوری که `p(x, coeff)` مقدار را در {eq}`polynom0` با توجه به نقطه `x` و لیست ضرایب `coeff` ($a_1, a_2, \cdots a_n$) محاسبه کند. -سعی کنید از `enumerate()` در حلقه خود استفاده کنید. +سعی کنید از `()enumerate` در حلقه خود استفاده کنید. ```{exercise-end} ``` @@ -877,7 +872,7 @@ p(x) ```{solution-start} pyess_ex2 :class: dropdown ``` -یک راه‌حل اینجاست: +یک راه‌حل این است: ```{code-cell} python3 def p(x, coeff): @@ -912,7 +907,7 @@ p(1, (2, 4)) :class: dropdown ``` -یک راه‌حل اینجاست: +یک راه‌حل این است: ```{code-cell} python3 def f(string): @@ -925,7 +920,7 @@ def f(string): f('The Rain in Spain') ``` -یک جایگزین، راه‌حل pythonic‌تر: +یک راه حل جایگزین‌ و پایتونی تر: ```{code-cell} python3 def count_uppercase_chars(s): @@ -952,7 +947,7 @@ count_uppercase_chars('The Rain in Spain') :class: dropdown ``` -یک راه‌حل اینجاست: +یک راه‌حل این است: ```{code-cell} python3 def f(seq_a, seq_b): @@ -968,7 +963,7 @@ print(f([1, 2], [1, 2, 3])) print(f([1, 2, 3], [1, 2])) ``` -یک جایگزین، راه‌حل pythonic‌تر با استفاده از `all()`: +یک راه حل جایگزین، پایتونی‌تر با استفاده از `()all`: ```{code-cell} python3 def f(seq_a, seq_b): @@ -981,7 +976,7 @@ print(f([1, 2], [1, 2, 3])) print(f([1, 2, 3], [1, 2])) ``` -البته، اگر از نوع داده `sets` استفاده کنیم، راه‌حل ساده‌تر است +البته، اگر از نوع داده `sets` استفاده کنیم، راه‌حل ساده‌تر است: ```{code-cell} python3 def f(seq_a, seq_b): @@ -1014,7 +1009,7 @@ def f(seq_a, seq_b): ```{solution-start} pyess_ex5 :class: dropdown ``` -یک راه‌حل اینجاست: +یک راه‌حل این است: ```{code-cell} python3 def linapprox(f, a, b, n, x): @@ -1061,7 +1056,7 @@ def linapprox(f, a, b, n, x): :label: pyess_ex6 ``` -با استفاده از نحو list comprehension، می‌توانیم حلقه در کد زیر را ساده کنیم. +با استفاده از سینتکس خلاصه لیست، می‌توانیم حلقه در کد زیر را ساده کنیم. ```{code-cell} python3 import numpy as np @@ -1080,7 +1075,7 @@ for i in range(n): :class: dropdown ``` -یک راه‌حل اینجاست. +یک راه‌حل این است: ```{code-cell} python3 n = 100 From b36e2215e476807a6e093b0e6e5b6e025e22f649 Mon Sep 17 00:00:00 2001 From: Zahra-khanzadeh Date: Mon, 5 Jan 2026 14:01:30 +0330 Subject: [PATCH 6/7] Update oop_intro lecture content and TOC --- lectures/_toc.yml | 2 +- lectures/oop_intro.md | 170 +++++++++++++++++++++--------------------- 2 files changed, 85 insertions(+), 87 deletions(-) diff --git a/lectures/_toc.yml b/lectures/_toc.yml index 524b302..532f9ca 100644 --- a/lectures/_toc.yml +++ b/lectures/_toc.yml @@ -9,7 +9,7 @@ parts: - file: python_by_example - file: functions # - file: python_essentials - # - file: oop_intro + - file: oop_intro # - file: names # - file: python_oop # - file: workspace diff --git a/lectures/oop_intro.md b/lectures/oop_intro.md index dcd8d7f..9eb761a 100644 --- a/lectures/oop_intro.md +++ b/lectures/oop_intro.md @@ -8,7 +8,7 @@ kernelspec: language: python name: python3 heading-map: - overview: مروری کلی + overview: مقدمه objects: اشیاء type: نوع identity: شناسه @@ -29,45 +29,45 @@ heading-map: ``` -# OOP I: اشیاء و متدها +# برنامه‌نویسی شی‌گرا قسمت اول : اشیاء و متدها -## مروری کلی +## مقدمه -پارادایم سنتی برنامه‌نویسی (مانند Fortran، C، MATLAB و غیره) [رویه‌ای](https://en.wikipedia.org/wiki/Procedural_programming) نامیده می‌شود. +در گذشته، بیشتر زبان های برنامه‌نویسی مانند (Fortran، C، MATLAB و غیره) بر اساس پارادایمی به نام «برنامه‌نویسی [رویه‌ای](https://en.wikipedia.org/wiki/Procedural_programming)» طراحی شده بودند. در این پارادایم، برنامه به صورت مجموعه‌ای از دستورالعمل ها و توابع نوشته می‌شود که به ترتیب اجرا شده و داده‌ها را پردازش می‌کند. -این پارادایم به شرح زیر عمل می‌کند +این پارادایم به شرح زیر عمل می‌کند: -* برنامه دارای یک وضعیت متناظر با مقادیر متغیرهای خود است. -* توابع فراخوانی می‌شوند تا بر روی وضعیت عمل کرده و آن را تغییر دهند. -* خروجی‌های نهایی از طریق توالی‌ای از فراخوانی‌های تابع تولید می‌شوند. +* برنامه دارای یک وضعیت است که متناظر با مقادیر متغیرهای خود است. +* توابع فراخوانی می‌شوند تا بر روی این وضعیت عمل کرده و آن را تغییر دهند. +* خروجی‌های نهایی از طریق دنباله‌ای از فراخوانی‌های توابع تولید می‌شوند. دو پارادایم مهم دیگر، [برنامه‌نویسی شی‌گرا](https://en.wikipedia.org/wiki/Object-oriented_programming) (OOP) و [برنامه‌نویسی تابعی](https://en.wikipedia.org/wiki/Functional_programming) هستند. -در پارادایم OOP، داده‌ها و توابع با هم در "اشیاء" بسته‌بندی می‌شوند --- و توابع در این زمینه به عنوان **متدها** شناخته می‌شوند. +در پارادایم OOP، داده‌ها و توابع در قالب "اشیاء" با یکدیگر ترکیب می‌شوند، و توابع در این زمینه به عنوان **متدها** شناخته می‌شوند. متدها برای تغییر داده‌های موجود در شیء فراخوانی می‌شوند. -* به یک لیست Python فکر کنید که حاوی داده است و متدهایی مانند `append()` و `pop()` دارد که داده را تغییر می‌دهند. +* به یک لیست پایتون فکر کنید که حاوی داده است و متدهایی مانند `()append` و `()pop` دارد که داده را تغییر می‌دهند. -زبان‌های برنامه‌نویسی تابعی بر اساس ایده ترکیب توابع ساخته شده‌اند. +زبان‌های برنامه‌نویسی تابعی، بر اساس ایده ترکیب توابع ساخته شده‌اند. -* نمونه‌های تأثیرگذار شامل [Lisp](https://en.wikipedia.org/wiki/Common_Lisp)، [Haskell](https://en.wikipedia.org/wiki/Haskell) و [Elixir](https://en.wikipedia.org/wiki/Elixir_(programming_language)) هستند. +* نمونه‌های معروف این دسته شامل [Lisp](https://en.wikipedia.org/wiki/Common_Lisp)، [Haskell](https://en.wikipedia.org/wiki/Haskell) و [Elixir](https://en.wikipedia.org/wiki/Elixir_(programming_language)) هستند. -پس Python در کدام یک از این دسته‌ها قرار می‌گیرد؟ +پس پایتون در کدام یک از این دسته‌ها قرار می‌گیرد؟ -در واقع Python یک زبان عمل‌گرا است که سبک‌های شی‌گرا، تابعی و رویه‌ای را ترکیب می‌کند، به جای اینکه رویکردی خالص داشته باشد. +در واقع پایتون یک زبان عمل‌گرا است که به جای پیروی سخت گیرانه از یک رویکرد خالص، سبک‌های شی‌گرا، تابعی و رویه‌ای را با یکدیگر ترکیب می‌کند. -از یک طرف، این امکان را به Python و کاربران آن می‌دهد تا جنبه‌های خوب پارادایم‌های مختلف را انتخاب کنند. +از یک طرف، این ویژگی به پایتون و کاربرانش اجازه می‌دهد تا جنبه‌های خوب پارادایم‌های مختلف را انتخاب کنند. -از طرف دیگر، فقدان خلوص ممکن است گاهی اوقات منجر به برخی سردرگمی‌ها شود. +و از طرف دیگر، همین نبود خلوص پارادایمی ممکن است گاهی اوقات منجر به برخی سردرگمی‌ها شود. -خوشبختانه این سردرگمی به حداقل می‌رسد اگر درک کنید که، در سطح بنیادی، Python شی‌گرا *است*. +خوشبختانه اگر بدانیم که در سطح بنیادی، پایتون یک زبان شی‌گرا *است*، این سردرگمی تا حد زیادی به حداقل می‌رسد. -منظور ما این است که، در Python، *همه چیز یک شیء است*. +منظور ما این است که، در پایتون، *همه چیز یک شیء است*. -در این سخنرانی، توضیح می‌دهیم که این گزاره به چه معناست و چرا اهمیت دارد. +در این درس، توضیح می‌دهیم که این گزاره به چه معناست و چرا اهمیت دارد. -ما از کتابخانه شخص ثالث زیر استفاده خواهیم کرد +ما از کتابخانه خارجی زیر استفاده خواهیم کرد: ```{code-cell} python3 :tags: [hide-output] @@ -79,24 +79,24 @@ heading-map: ```{index} single: Python; Objects ``` -در Python، یک *شیء* مجموعه‌ای از داده‌ها و دستورالعمل‌های نگهداری‌شده در حافظه کامپیوتر است که شامل موارد زیر می‌شود +در پایتون، یک *شیء* مجموعه‌ای از داده‌ها و دستورالعمل‌های نگهداری‌شده در حافظه کامپیوتر است که شامل موارد زیر می‌شود: -1. یک نوع -1. یک شناسه منحصر به فرد +1. یک نوع(Type) +1. یک شناسه منحصر به فرد(Unique Identity) 1. داده (یعنی محتوا) -1. متدها +1. متدها(Methods) -این مفاهیم به ترتیب تعریف و بحث می‌شوند. +این مفاهیم به ترتیب تعریف و بررسی می‌شوند. (type)= -### نوع +### نوع (Type) ```{index} single: Python; Type ``` -Python برای انواع مختلف اشیاء فراهم می‌کند تا دسته‌های مختلف داده را در بر گیرد. +پایتون انواع مختلفی از اشیاء را فراهم می‌کند تا بتواند دسته‌های مختلفی از داده ها را پشتیبانی کند. -به عنوان مثال +به عنوان مثال: ```{code-cell} python3 s = 'This is a string' @@ -110,19 +110,19 @@ type(x) نوع یک شیء برای بسیاری از عبارات مهم است. -به عنوان مثال، عملگر جمع بین دو رشته به معنای الحاق است +به عنوان مثال، عملگر جمع بین دو رشته متنی به معنای به هم پیوند دادن آنها است: ```{code-cell} python3 '300' + 'cc' ``` -از طرف دیگر، بین دو عدد به معنای جمع معمولی است +از طرف دیگر، بین دو عدد به معنای جمع معمولی است: ```{code-cell} python3 300 + 400 ``` -عبارت زیر را در نظر بگیرید +عبارت زیر را در نظر بگیرید: ```{code-cell} python3 --- @@ -131,33 +131,33 @@ tags: [raises-exception] '300' + 400 ``` -در اینجا ما در حال ترکیب انواع هستیم، و برای Python مشخص نیست که آیا کاربر می‌خواهد +در اینجا ما در حال ترکیب انواع متفاوتی از مقادیر هستیم، و برای پایتون مشخص نیست که آیا کاربر می‌خواهد: * `'300'` را به عدد صحیح تبدیل کند و سپس آن را به `400` اضافه کند، یا -* `400` را به رشته تبدیل کند و سپس آن را با `'300'` الحاق کند +* `400` را به رشته تبدیل کند و سپس آن را به `'300'` متصل کند. -برخی زبان‌ها ممکن است سعی کنند حدس بزنند اما Python *به شدت تایپ‌شده* است +برخی زبان‌ها ممکن است سعی کنند حدس بزنند، اما پایتون یک زبان *تایپ قوی (strongly typed)* است. -* نوع مهم است، و تبدیل ضمنی نوع نادر است. -* Python در عوض با بالا آوردن یک `TypeError` پاسخ می‌دهد. +* نوع داده اهمیت زیادی دارد و تبدیل ضمنی نوع در پایتون به ندرت انجام می‌شود. +* در نتیجه پایتون به جای حدس زدن، با نشان دادن یک خطای `TypeError` پاسخ می‌دهد. -برای جلوگیری از خطا، باید با تغییر نوع مربوطه توضیح دهید. +برای جلوگیری از این خطا، باید با تغییر نوع داده مربوطه، منظور خود را به صورت صریح وشفاف مشخص کنید. -به عنوان مثال، +به عنوان مثال: ```{code-cell} python3 int('300') + 400 # برای جمع به عنوان اعداد، رشته را به عدد صحیح تبدیل کنید ``` (identity)= -### شناسه +### شناسه (Unique Identity) ```{index} single: Python; Identity ``` -در Python، هر شیء یک شناسه منحصر به فرد دارد که به Python (و ما) کمک می‌کند تا شیء را پیگیری کند. +در پایتون، هر شیء یک شناسه منحصر به فرد دارد که به پایتون (و ما) کمک می‌کند تا شیء را ردیابی و تشخیص دهیم. -شناسه یک شیء را می‌توان از طریق تابع `id()` به دست آورد +شناسه یک شیء را می‌توان از طریق تابع `()id` به دست آورد: ```{code-cell} python3 y = 2.5 @@ -169,7 +169,7 @@ id(y) id(z) ``` -در این مثال، `y` و `z` اتفاقاً مقدار یکسانی (یعنی `2.5`) دارند، اما آن‌ها یک شیء نیستند. +در این مثال، `y` و `z` با اینکه مقدار یکسانی (یعنی `2.5`) دارند، اما آن‌ها یک شیء نیستند. شناسه یک شیء در واقع فقط آدرس شیء در حافظه است. @@ -178,10 +178,9 @@ id(z) ```{index} single: Python; Content ``` -اگر `x = 42` را تنظیم کنیم، یک شیء از نوع `int` ایجاد می‌کنیم که حاوی داده `42` است. - -در واقع، حاوی چیزهای بیشتری است، همانطور که مثال زیر نشان می‌دهد +اگر `x = 42` را قرار دهیم، یک شیء از نوع `int` ایجاد می‌کنیم که حاوی داده `42` است. +در واقع، همانطور که مثال زیر نشان می‌دهد، حاوی اطلاعات بیشتری نیز هست: ```{code-cell} python3 x = 42 x @@ -195,17 +194,17 @@ x.imag x.__class__ ``` -وقتی Python این شیء عدد صحیح را ایجاد می‌کند، اطلاعات کمکی مختلفی مانند قسمت موهومی و نوع را با آن ذخیره می‌کند. +وقتی پایتون این شیء که از نوع عدد صحیح است را ایجاد می‌کند، اطلاعات کمکی مختلفی مانند قسمت موهومی(imaginary) و نوع(type) شیء را با آن ذخیره می‌کند. -هر نامی که بعد از نقطه می‌آید یک *ویژگی* از شیء سمت چپ نقطه نامیده می‌شود. +هر نامی که بعد از نقطه بیاید *ویژگی(attribute)* شیء سمت چپ نقطه نامیده می‌شود. * به عنوان مثال، `imag` و `__class__` ویژگی‌های `x` هستند. از این مثال می‌بینیم که اشیاء دارای ویژگی‌هایی هستند که حاوی اطلاعات کمکی هستند. -آن‌ها همچنین دارای ویژگی‌هایی هستند که مانند توابع عمل می‌کنند، به نام *متدها*. + همچنین، ویژگی‌هایی وجود دارند که مانند توابع عمل می‌کنند و *متد(methods)* نامیده می‌شوند -این ویژگی‌ها مهم هستند، بنابراین بیایید آن‌ها را به طور عمیق بحث کنیم. +این ویژگی‌ها مهم هستند، بنابراین بیایید آن‌ها را به طور عمیق بررسی کنیم. (methods)= ### متدها @@ -213,9 +212,9 @@ x.__class__ ```{index} single: Python; Methods ``` -متدها *توابعی هستند که با اشیاء بسته‌بندی می‌شوند*. +متدها *توابعی هستند که به طور مستقیم با یک شیء مرتبط شده و جزئی از آن شیء محسوب می‌شوند*. -به طور رسمی، متدها ویژگی‌های اشیاء هستند که **قابل فراخوانی** هستند -- یعنی ویژگی‌هایی که می‌توانند به عنوان تابع فراخوانی شوند +به طور رسمی، متدها ویژگی‌های اشیاء هستند که **قابل فراخوانی** هستند، یعنی ویژگی‌هایی که می‌توان آن ها را مانند توابع فراخوانی کرد. ```{code-cell} python3 x = ['foo', 'bar'] @@ -226,7 +225,7 @@ callable(x.append) callable(x.__doc__) ``` -متدها معمولاً بر روی داده‌های موجود در شیئی که به آن تعلق دارند عمل می‌کنند، یا آن داده را با داده‌های دیگر ترکیب می‌کنند +متدها معمولاً بر روی داده‌های موجود در شیئی که به آن تعلق دارند عمل می‌کنند، یا آن داده را با داده‌های دیگر ترکیب می‌کنند: ```{code-cell} python3 x = ['a', 'b'] @@ -243,19 +242,19 @@ s.lower() s.replace('This', 'That') ``` -بخش بزرگی از قابلیت‌های Python حول فراخوانی‌های متد سازماندهی شده است. +بخش بزرگی از قابلیت‌های پایتون حول فراخوانی‌های متدها سازماندهی شده است. -به عنوان مثال، کد زیر را در نظر بگیرید +به عنوان مثال، کد زیر را در نظر بگیرید: ```{code-cell} python3 x = ['a', 'b'] -x[0] = 'aa' # انتساب آیتم با استفاده از نماد براکت مربعی +x[0] = 'aa' # تغییر آیتم با استفاده از براکت x ``` -به نظر نمی‌رسد که در اینجا از هیچ متدی استفاده شده باشد، اما در واقع نماد انتساب براکت مربعی فقط یک رابط راحت برای فراخوانی متد است. +با اینکه به نظر می‌رسد که در اینجا از هیچ متدی استفاده نشده باشد، اما در واقع استفاده از براکت ها برای تغییر دادن مقادیر فقط یک رابط ساده و راحت برای فراخوانی یک متد است. -آنچه در واقع اتفاق می‌افتد این است که Python متد `__setitem__` را فراخوانی می‌کند، به شرح زیر +آنچه در واقع اتفاق می‌افتد این است که پایتون متد `__setitem__` را به شرح زیر فراخوانی می‌کند: ```{code-cell} python3 x = ['a', 'b'] @@ -263,32 +262,31 @@ x.__setitem__(0, 'aa') # معادل x[0] = 'aa' x ``` -(اگر بخواهید می‌توانید متد `__setitem__` را تغییر دهید، به طوری که انتساب براکت مربعی کار کاملاً متفاوتی انجام دهد) +(اگر بخواهید می‌توانید متد `__setitem__` را تغییر دهید، به طوری که استفاده از براکت ها برای مقادیر کار کاملاً متفاوتی انجام دهد) ## بازرسی با استفاده از Rich -یک بسته خوب به نام [rich](https://github.com/Textualize/rich) وجود دارد که به ما کمک می‌کند محتویات یک شیء را مشاهده کنیم. +یک بسته بسیار کاربردی به نام [rich](https://github.com/Textualize/rich) وجود دارد که به ما کمک می‌کند محتویات یک شیء را به صورت خوانا مشاهده کنیم. -به عنوان مثال، +به عنوان مثال: ```{code-cell} python3 from rich import inspect x = 10 inspect(10) ``` -اگر بخواهیم متدها را نیز ببینیم، می‌توانیم استفاده کنیم - +برای دیدن متدها هم میتوانیم از این روش استفاده کنیم: ```{code-cell} python3 inspect(10, methods=True) ``` -در واقع متدهای بیشتری وجود دارند، همانطور که می‌توانید ببینید اگر `inspect(10, all=True)` را اجرا کنید. +در واقع متدهای بیشتری هم وجود دارند، و شما می‌توانید با اجرای `inspect(10, all=True)` آنها را مشاهده کنید. ## یک معمای کوچک -در این سخنرانی ادعا کردیم که Python، در قلب، یک زبان شی‌گرا است. +در این سخنرانی ادعا کردیم که پایتون، در ذات خود یک زبان شی‌گرا است. -اما در اینجا مثالی وجود دارد که بیشتر رویه‌ای به نظر می‌رسد. +اما در اینجا مثالی وجود دارد که بیشتر رویه‌ای به نظر می‌رسد: ```{code-cell} python3 x = ['a', 'b'] @@ -296,27 +294,27 @@ m = len(x) m ``` -اگر Python شی‌گرا است، چرا از `x.len()` استفاده نمی‌کنیم؟ +اگر پایتون شی‌گرا است، چرا از `()x.len` استفاده نمی‌کنیم؟ -پاسخ به این واقعیت مربوط است که Python برای خوانایی و سبک ثابت تلاش می‌کند. +پاسخ به این نکته مربوط می‌شود به اینکه پایتون به قابلیت خوانایی و سبک ثابت و یکسان اهمیت می‌دهد. -در Python، معمول است که کاربران اشیاء سفارشی بسازند --- ما نحوه انجام این کار را {doc}`بعداً ` بحث می‌کنیم. +در پایتون، معمولا کاربران اشیاء سفارشی می‌سازند، ما نیز نحوه انجام این کار را {doc}`بعداً ` بررسی خواهیم. -کاملاً رایج است که کاربران متدهایی به اشیاء خود اضافه کنند که طول شیء را، به طور مناسب تعریف شده، اندازه‌گیری کنند. +معمولا کاربران متدهایی به اشیاء خود اضافه می‌کنند که طول شیء را، به طوریکه برای شیء مناسب باشد، اندازه‌گیری کنند. -هنگام نام‌گذاری چنین متدی، انتخاب‌های طبیعی `len()` و `length()` هستند. +هنگام نام‌گذاری چنین متدی، انتخاب‌های طبیعی `()len` و `()length` هستند. -اگر برخی از کاربران `len()` و دیگران `length()` را انتخاب کنند، سبک ناسازگار و سخت‌تر برای به خاطر سپردن خواهد بود. +اگر برخی از کاربران `()len` و برخی دیگر `()length` را انتخاب کنند، سبک ناسازگار و ناهماهنگ شده و به خاطر سپردن آن سخت تر خواهد بود. -برای جلوگیری از این امر، سازنده Python تصمیم گرفت `len()` را به عنوان یک تابع داخلی اضافه کند، تا به تأکید بر اینکه `len()` قرارداد است کمک کند. +برای جلوگیری از این امر، سازنده پایتون تصمیم گرفت `()len` را به عنوان یک تابع داخلی اضافه کند، تا تأکید کند بر اینکه استفاده از `()len` قراردادی است. -حالا، با گفتن همه این‌ها، Python همچنان در زیر پوشش شی‌گرا *است*. +حالا، با گفتن همه این‌ها، پایتون همچنان در پشت صحنه شی‌گرا *است*. -در واقع، لیست `x` مورد بحث بالا دارای متدی به نام `__len__()` است. +در واقع، لیست `x` که پیشتر بررسی شد، دارای متدی به نام `()__len__` است. -تنها کاری که تابع `len()` انجام می‌دهد فراخوانی این متد است. +و تنها کاری که تابع `()len` انجام می‌دهد فراخوانی این متد است. -به عبارت دیگر، کد زیر معادل است: +به عبارت دیگر، معادل کد زیر است: ```{code-cell} python3 x = ['a', 'b'] @@ -331,18 +329,18 @@ x.__len__() ## خلاصه -پیام این سخنرانی واضح است: +نکته اصلی این درس این است: -* در Python، *همه چیز در حافظه به عنوان یک شیء در نظر گرفته می‌شود*. +* در پایتون، *همه چیز در حافظه به عنوان یک شیء در نظر گرفته می‌شود*. -این شامل نه فقط لیست‌ها، رشته‌ها و غیره، بلکه چیزهای کمتر آشکار، مانند +و این فقط شامل لیست‌ها، رشته‌ها و غیره نیست، بلکه مواردی که کمتر مورد توجه قرار میگیرد را نیز شامل می‌شود، مانند: -* توابع (پس از خواندن در حافظه) -* ماژول‌ها (همان‌طور) +* توابع (پس از بارگذاری در حافظه) +* ماژول‌ها * فایل‌های باز شده برای خواندن یا نوشتن * اعداد صحیح و غیره -به یاد داشتن اینکه همه چیز یک شیء است به شما کمک می‌کند تا با برنامه‌های خود تعامل کنید و کد Pythonic واضحی بنویسید. +به یاد داشتن اینکه همه چیز یک شیء است به شما کمک می‌کند تا با برنامه‌های خود تعامل داشته باشید و کد پایتونی واضحی بنویسید. ## تمرین‌ها @@ -352,7 +350,7 @@ x.__len__() ما قبلاً با {any}`نوع داده بولین ` آشنا شدیم. -با استفاده از آنچه در این سخنرانی آموختیم، لیستی از متدهای شیء بولین `True` را چاپ کنید. +با استفاده از آنچه در این درس آموختیم، لیستی از متدهای شیء بولین `True` را چاپ کنید. ```{hint} :class: dropdown @@ -367,7 +365,7 @@ x.__len__() :class: dropdown ``` -ابتدا، باید همه ویژگی‌های `True` را پیدا کنیم، که می‌تواند از طریق این انجام شود +ابتدا، باید همه ویژگی‌های `True` را پیدا کنیم، که با کد زیر میتوانید پیدا کنید: ```{code-cell} python3 print(sorted(True.__dir__())) @@ -379,13 +377,13 @@ print(sorted(True.__dir__())) print(sorted(dir(True))) ``` -از آنجایی که نوع داده بولین یک نوع اولیه است، می‌توانید آن را در فضای نام داخلی نیز پیدا کنید +از آنجایی که نوع داده بولین یک نوع داده اولیه است، می‌توانید آن را در مجموعه پیش فرض توابع و نام ها (built-in) نیز پیدا کنید: ```{code-cell} python3 print(dir(__builtins__.bool)) ``` -در اینجا از یک حلقه `for` برای فیلتر کردن ویژگی‌هایی که قابل فراخوانی هستند استفاده می‌کنیم +در اینجا از یک حلقه `for` برای فیلتر کردن ویژگی‌هایی که قابل فراخوانی هستند استفاده می‌کنیم: ```{code-cell} python3 attributes = dir(__builtins__.bool) From 47269897dedbf2b10859f5417f4b5c9e74cadb2f Mon Sep 17 00:00:00 2001 From: Zahra-khanzadeh Date: Wed, 7 Jan 2026 13:23:15 +0330 Subject: [PATCH 7/7] Update names lecture content and TOC --- lectures/_toc.yml | 2 +- lectures/names.md | 228 +++++++++++++++++++++++----------------------- 2 files changed, 115 insertions(+), 115 deletions(-) diff --git a/lectures/_toc.yml b/lectures/_toc.yml index 524b302..3277770 100644 --- a/lectures/_toc.yml +++ b/lectures/_toc.yml @@ -10,7 +10,7 @@ parts: - file: functions # - file: python_essentials # - file: oop_intro - # - file: names + - file: names # - file: python_oop # - file: workspace # - caption: The Scientific Libraries diff --git a/lectures/names.md b/lectures/names.md index 28a6274..e9e3a61 100644 --- a/lectures/names.md +++ b/lectures/names.md @@ -8,15 +8,15 @@ kernelspec: language: python name: python3 heading-map: - overview: مرور کلی - variable-names-in-python: نام‌های متغیر در Python + overview: مقدمه + variable-names-in-python: نام‌های متغیر در پایتون namespaces: فضاهای نام viewing-namespaces: مشاهده فضاهای نام - interactive-sessions: جلسات تعاملی - the-global-namespace: فضای نام عمومی + interactive-sessions: محیط تعاملی + the-global-namespace: فضای نام سراسری local-namespaces: فضاهای نام محلی - the-__builtins__-namespace: فضای نام `__builtins__` - name-resolution: تفکیک نام + the-__builtins__-namespace: فضای نام داخلی (The `__builtins__` Namespace ) + name-resolution: Name Resolution indexmutable-single-mutable-versus-indeximmutable-single-immutable-parameters: 'پارامترهای {index}`تغییرپذیر ` در مقابل {index}`تغییرناپذیر `' --- @@ -31,38 +31,38 @@ heading-map: # نام‌ها و فضاهای نام -## مرور کلی +## مقدمه -این درس تماماً درباره نام‌های متغیر، نحوه استفاده از آن‌ها و نحوه درک آن‌ها توسط مفسر Python است. +این درس کاملا درباره نام‌ متغیرها است،اینکه چگونه استفاده می‌شوند و مفسر پایتون چگونه آن ها را درک می‌کند. -ممکن است این موضوع کمی خسته‌کننده به نظر برسد، اما مدلی که Python برای مدیریت نام‌ها اتخاذ کرده است، ظریف و جالب است. +ممکن است این موضوع کمی خسته‌کننده به نظر برسد، اما مدلی که پایتون برای مدیریت نام‌ها اتخاذ کرده است، ظریف و جالب است. -علاوه بر این، اگر درک خوبی از نحوه کار نام‌ها در Python داشته باشید، ساعت‌های زیادی را از اشکال‌زدایی صرفه‌جویی خواهید کرد. +علاوه بر این، اگر درک خوبی از نحوه کار نام‌ها در پایتون داشته باشید، ساعت‌های زیادی را برای اشکال‌زدایی صرف نخواهید کرد. (var_names)= -## نام‌های متغیر در Python +## نام‌های متغیر در پایتون ```{index} single: Python; Variable Names ``` -دستور Python زیر را در نظر بگیرید +دستور پایتون زیر را در نظر بگیرید: ```{code-cell} python3 x = 42 ``` -اکنون می‌دانیم که وقتی این دستور اجرا می‌شود، Python یک شیء از نوع `int` در حافظه کامپیوتر شما ایجاد می‌کند که شامل موارد زیر است: +اکنون می‌دانیم که وقتی این دستور اجرا می‌شود، پایتون یک شیء از نوع `int` در حافظه کامپیوتر شما ایجاد می‌کند که شامل موارد زیر است: * مقدار `42` * برخی صفات مرتبط اما خود `x` چیست؟ -در Python، `x` یک **نام** نامیده می‌شود، و دستور `x = 42` نام `x` را به شیء عدد صحیح که تازه در موردش صحبت کردیم **متصل** می‌کند. +در پایتون، `x` یک **نام** نامیده می‌شود، و دستور `x = 42` نام `x` را به شیء عدد صحیح که تازه در موردش صحبت کردیم **متصل** می‌کند. -در پشت صحنه، این فرآیند اتصال نام‌ها به اشیاء به عنوان یک دیکشنری پیاده‌سازی می‌شود - بیشتر درباره این موضوع در ادامه خواهیم گفت. +در پشت صحنه، این فرآیند اتصال نام‌ها به اشیاء به عنوان یک دیکشنری پیاده‌سازی می‌شود، که درباره این موضوع در ادامه بیشتر خواهیم گفت. -هیچ مشکلی برای اتصال دو یا چند نام به یک شیء وجود ندارد، صرف‌نظر از اینکه آن شیء چه باشد +هیچ مشکلی برای اتصال دو یا چند نام به یک شیء وجود ندارد، صرف‌نظر از اینکه آن شیء چه باشد: ```{code-cell} python3 def f(string): # Create a function called f @@ -76,7 +76,7 @@ id(g) == id(f) g('test') ``` -در مرحله اول، یک شیء تابع ایجاد می‌شود و نام `f` به آن متصل می‌شود. +در مرحله اول، یک شیء تابع(function object) ایجاد می‌شود و نام `f` به آن متصل(bind) می‌شود. پس از اتصال نام `g` به همان شیء، می‌توانیم از آن در هر جایی که از `f` استفاده می‌کنیم، استفاده کنیم. @@ -91,13 +91,13 @@ x = 'bar' id(x) ``` -در این مورد، پس از اینکه `x` را مجدداً به `'bar'` متصل می‌کنیم، هیچ نامی به شیء اول `'foo'` متصل نیست. +در این مورد، پس از اینکه `x` را دوباره به `'bar'` متصل می‌کنیم، دیگر هیچ نامی به شیء اول یعنی `'foo'` متصل نیست. -این یک محرک برای جمع‌آوری زباله `'foo'` است. +این وضعیت باعث می‌شود که `'foo'` وارد فرآیند جمع‌آوری زباله (garbage collection) شود. به عبارت دیگر، جای حافظه‌ای که آن شیء را ذخیره می‌کند، آزاد می‌شود و به سیستم عامل بازگردانده می‌شود. -جمع‌آوری زباله در واقع یک حوزه تحقیقاتی فعال در علوم کامپیوتر است. +جمع‌آوری زباله در واقع یکی از حوزه های فعال پژوهشی در علوم کامپیوتر است. اگر علاقه‌مند هستید، می‌توانید [بیشتر درباره جمع‌آوری زباله بخوانید](https://rushter.com/blog/python-garbage-collector/). @@ -106,46 +106,46 @@ id(x) ```{index} single: Python; Namespaces ``` -از بحث قبلی به یاد بیاورید که دستور +در بحث قبلی دستور زیر را نوشتیم: ```{code-cell} python3 x = 42 ``` -نام `x` را به شیء عدد صحیح در سمت راست متصل می‌کند. +این دستور نام `x` را به عدد صحیح در سمت راست متصل می‌کند. همچنین ذکر کردیم که این فرآیند اتصال `x` به شیء صحیح به عنوان یک دیکشنری پیاده‌سازی می‌شود. این دیکشنری، فضای نام نامیده می‌شود. ```{admonition} تعریف -یک **فضای نام** یک جدول نمادها است که نام‌ها را به اشیاء در حافظه نگاشت می‌کند. +یک **فضای نام** یک جدول از نمادها است که به پایتون می‌گوید هر اسم مربوط به کدام شیء در حافظه است. ``` -Python از چندین فضای نام استفاده می‌کند و در صورت لزوم آن‌ها را به صورت پویا ایجاد می‌کند. +پایتون از چندین فضای نام استفاده می‌کند و در صورت لزوم آن‌ها را به صورت پویا ایجاد می‌کند. -به عنوان مثال، هر بار که ماژولی را import می‌کنیم، Python یک فضای نام برای آن ماژول ایجاد می‌کند. +به عنوان مثال، هر بار که ماژولی را import می‌کنیم، پایتون یک فضای نام برای آن ماژول ایجاد می‌کند. -برای مشاهده این موضوع در عمل، فرض کنید یک اسکریپت `mathfoo.py` با یک خط می‌نویسیم +برای مشاهده این موضوع در عمل، فرض کنید اسکریپتی به نام `mathfoo.py` می‌نویسیم که فقط یک خط دارد: ```{code-cell} python3 %%file mathfoo.py pi = 'foobar' ``` -حالا مفسر Python را شروع می‌کنیم و آن را import می‌کنیم +حالا مفسر پایتون را شروع می‌کنیم و آن را import می‌کنیم: ```{code-cell} python3 import mathfoo ``` -بعد بیایید ماژول `math` را از کتابخانه استاندارد import کنیم +بعد بیایید ماژول `math` را از کتابخانه استاندارد import کنیم: ```{code-cell} python3 import math ``` -هر دوی این ماژول‌ها یک صفت به نام `pi` دارند +هر دوی این ماژول‌ها یک صفت به نام `pi` دارند: ```{code-cell} python3 math.pi @@ -155,9 +155,9 @@ math.pi mathfoo.pi ``` -این دو اتصال متفاوت `pi` در فضاهای نام متفاوتی وجود دارند که هر کدام به عنوان یک دیکشنری پیاده‌سازی شده‌اند. +این دو اتصال متفاوت `pi` در دو فضای نام جداگانه وجود دارند و هر کدام به صورت یک دیکشنری پیاده‌سازی شده‌اند. -اگر بخواهید، می‌توانید مستقیماً به دیکشنری نگاه کنید، با استفاده از `module_name.__dict__`. +اگر بخواهید، می‌توانید این دیکشنری را مستقیما با استفاده از `module_name.__dict__` نگاه کنید: ```{code-cell} python3 import math @@ -171,13 +171,13 @@ import mathfoo mathfoo.__dict__ ``` -همان‌طور که می‌دانید، ما با استفاده از نشانه‌گذاری صفت نقطه‌دار به عناصر فضای نام دسترسی پیدا می‌کنیم +همان‌طور که می‌دانید، ما به عناصر موجود در فضای نام، با استفاده از نقطه‌گذاری صفات دسترسی پیدا می‌کنیم. ```{code-cell} python3 math.pi ``` -این کاملاً معادل `math.__dict__['pi']` است +این دستور کاملاً معادل `math.__dict__['pi']` است: ```{code-cell} python3 math.__dict__['pi'] @@ -185,15 +185,15 @@ math.__dict__['pi'] ## مشاهده فضاهای نام -همان‌طور که در بالا دیدیم، فضای نام `math` را می‌توان با تایپ کردن `math.__dict__` چاپ کرد. +همان‌طور که در بالا دیدیم، فضای نام `math` را می‌توان با تایپ کردن `math.__dict__` چاپ (print)کرد. -راه دیگر برای دیدن محتویات آن تایپ کردن `vars(math)` است +راه دیگر برای دیدن محتویات آن تایپ کردن `vars(math)` است: ```{code-cell} python3 vars(math).items() ``` -اگر فقط می‌خواهید نام‌ها را ببینید، می‌توانید تایپ کنید +اگر فقط می‌خواهید نام‌ها را ببینید، می‌توانید دستور زیر را تایپ کنید: ```{code-cell} python3 # Show the first 10 names @@ -202,7 +202,7 @@ dir(math)[0:10] به نام‌های ویژه `__doc__` و `__name__` توجه کنید. -این‌ها در فضای نام هنگام import کردن هر ماژول مقداردهی اولیه می‌شوند +این‌ نام ها به محض import شدن هر ماژول، به طور خودکار در فضای نام ایجاد و مقداردهی می‌شوند: * `__doc__` رشته مستندسازی ماژول است * `__name__` نام ماژول است @@ -215,18 +215,18 @@ print(math.__doc__) math.__name__ ``` -## جلسات تعاملی +## محیط تعاملی ```{index} single: Python; Interpreter ``` -در Python، **تمام** کدهایی که توسط مفسر اجرا می‌شوند در ماژولی اجرا می‌شوند. +در پایتون، **تمام** کدهایی که توسط مفسر اجرا می‌شوند داخل یک ماژول اجرا می‌شوند. -در مورد دستوراتی که در prompt تایپ می‌شوند چطور؟ +اما دستوراتی که مستقیما در محیط تعاملی (prompt) تایپ می‌کنیم چطور؟ -این‌ها نیز به عنوان اجرا شده در یک ماژول در نظر گرفته می‌شوند - در این مورد، ماژولی به نام `__main__`. +این‌ دستورها هم به عنوان کدی در نظر گرفته می‌شوند که داخل یک ماژول اجرا می‌شود؛ در این حالت، آن ماژول `__main__` نام دارد. -برای بررسی این موضوع، می‌توانیم نام ماژول فعلی را از طریق مقدار `__name__` که در prompt داده می‌شود مشاهده کنیم +برای بررسی این موضوع، می‌توانیم مقدار `__name__`را درprompt چاپ کنیم تا نام ماژول فعلی را ببینیم. ```{code-cell} python3 print(__name__) @@ -234,14 +234,14 @@ print(__name__) وقتی یک اسکریپت را با استفاده از دستور `run` در IPython اجرا می‌کنیم، محتویات فایل نیز به عنوان بخشی از `__main__` اجرا می‌شوند. -برای مشاهده این موضوع، بیایید یک فایل `mod.py` ایجاد کنیم که صفت `__name__` خودش را چاپ کند +برای مشاهده این موضوع، بیایید یک فایل `mod.py` ایجاد کنیم که صفت `__name__` خودش را چاپ کند: ```{code-cell} ipython %%file mod.py print(__name__) ``` -حالا بیایید دو روش متفاوت اجرای آن را در IPython ببینیم +حالا بیایید دو روش متفاوت اجرای آن را در IPython ببینیم: ```{code-cell} python3 import mod # Standard import @@ -253,11 +253,11 @@ import mod # Standard import در حالت دوم، کد به عنوان بخشی از `__main__` اجرا می‌شود، بنابراین `__name__` برابر با `__main__` است. -برای دیدن محتویات فضای نام `__main__` از `vars()` به جای `vars(__main__)` استفاده می‌کنیم. +برای دیدن محتویات فضای نام `__main__` از `()vars` به جای `vars(__main__)` استفاده می‌کنیم. -اگر این کار را در IPython انجام دهید، تعداد زیادی متغیر خواهید دید که IPython به آن‌ها نیاز دارد و هنگام شروع جلسه مقداردهی اولیه کرده است. +اگر این کار را در IPython انجام دهید، تعداد زیادی متغیر خواهید دید که IPython به آن‌ها نیاز دارد و هنگام شروع جلسه مقداردهی اولیه را انجام داده است. -اگر ترجیح می‌دهید فقط متغیرهایی که شما مقداردهی اولیه کرده‌اید را ببینید، از `%whos` استفاده کنید +اگر ترجیح می‌دهید فقط متغیرهایی که شما مقداردهی اولیه کرده‌اید را ببینید، از `whos%` استفاده کنید: ```{code-cell} ipython x = 2 @@ -268,20 +268,20 @@ import numpy as np %whos ``` -## فضای نام عمومی +## فضای نام سراسری یا جهانی(The Global Namespace) ```{index} single: Python; Namespace (Global) ``` -مستندات Python اغلب به "فضای نام عمومی" اشاره می‌کند. +مستندات پایتون اغلب به "فضای نام سراسری" اشاره می‌کند. -فضای نام عمومی *فضای نام ماژولی است که در حال حاضر در حال اجرا است*. +فضای نام سراسری *فضای نام ماژولی است که در حال حاضر در حال اجرا است*. -به عنوان مثال، فرض کنید که مفسر را شروع می‌کنیم و شروع به انجام انتسابات می‌کنیم. +به عنوان مثال، فرض کنید که مفسر را باز می‌کنیم و شروع به انجام تخصیص ها(assignments) می‌کنیم. -اکنون ما در ماژول `__main__` کار می‌کنیم، و از این رو فضای نام برای `__main__` فضای نام عمومی است. +اکنون ما در ماژول `__main__` کار می‌کنیم، و از این رو فضای نام برای `__main__` همان فضای نام سراسری است. -سپس، ماژولی به نام `amodule` را import می‌کنیم +سپس، ماژولی به نام `amodule` را import می‌کنیم: ```{code-block} python3 :class: no-execute @@ -291,13 +291,13 @@ import amodule در این نقطه، مفسر یک فضای نام برای ماژول `amodule` ایجاد می‌کند و شروع به اجرای دستورات در ماژول می‌کند. -در حالی که این اتفاق می‌افتد، فضای نام `amodule.__dict__` فضای نام عمومی است. +در حالی که این اتفاق می‌افتد، فضای نام `amodule.__dict__` فضای نام سراسری است. پس از اتمام اجرای ماژول، مفسر به ماژولی که دستور import از آن صادر شده بود بازمی‌گردد. -در این مورد `__main__` است، بنابراین فضای نام `__main__` دوباره فضای نام عمومی می‌شود. +در این مثال، این ماژول `__main__` است، بنابراین دوباره فضای نام مربوط به `__main__` به عنوان فضای نام سراسری درنظر گرفته می‌شود. -## فضاهای نام محلی +## فضای نام محلی(Local Namespaces) ```{index} single: Python; Namespace (Local) ``` @@ -310,9 +310,9 @@ import amodule پس از بازگشت تابع، فضای نام آزاد می‌شود و از بین می‌رود. -در حالی که تابع در حال اجرا است، می‌توانیم محتویات فضای نام محلی را با `locals()` مشاهده کنیم. +در حالی که تابع در حال اجرا است، می‌توانیم محتویات فضای نام محلی را با `()locals` مشاهده کنیم. -به عنوان مثال، در نظر بگیرید +به عنوان مثال، دستور زیر را در نظر بگیرید: ```{code-cell} python3 def f(x): @@ -321,7 +321,7 @@ def f(x): return a * x ``` -حالا بیایید تابع را فراخوانی کنیم +حالا بیایید تابع را فراخوانی کنیم: ```{code-cell} python3 f(1) @@ -329,17 +329,17 @@ f(1) می‌توانید فضای نام محلی `f` را قبل از نابود شدن ببینید. -## فضای نام `__builtins__` +## فضای نام داخلی (The `__builtins__` Namespace ) ```{index} single: Python; Namespace (__builtins__) ``` -ما از توابع داخلی مختلفی مانند `max(), dir(), str(), list(), len(), range(), type()` و غیره استفاده کرده‌ایم. +ما از توابع داخلی مختلفی مانند `()max` و `()dir` و `()str`و `()list` و `()len` و `()range` و `()type`و غیره، استفاده کرده‌ایم. -دسترسی به این نام‌ها چگونه کار می‌کند؟ +اما دسترسی به این نام‌ها چگونه امکان پذیر است؟ * این تعاریف در ماژولی به نام `__builtin__` ذخیره شده‌اند. -* آن‌ها فضای نام خاص خود را به نام `__builtins__` دارند. +* آن‌ها فضای نام مخصوص به خود را دارند که به آن `__builtins__` گفته می‌شود. ```{code-cell} python3 # Show the first 10 names in `__main__` @@ -351,13 +351,13 @@ dir()[0:10] dir(__builtins__)[0:10] ``` -می‌توانیم به عناصر فضای نام به صورت زیر دسترسی پیدا کنیم +می‌توانیم به عناصر فضای نام به صورت زیر دسترسی پیدا کنیم: ```{code-cell} python3 __builtins__.max ``` -اما `__builtins__` ویژه است، زیرا همیشه می‌توانیم مستقیماً به آن‌ها نیز دسترسی پیدا کنیم +اما `__builtins__` خاص است، چون همیشه می‌توانیم مستقیماً به آن‌ها هم دسترسی داشته باشیم. ```{code-cell} python3 max @@ -367,9 +367,9 @@ max __builtins__.max == max ``` -بخش بعدی توضیح می‌دهد که این چگونه کار می‌کند ... +بخش بعدی توضیح می‌دهد که این کار چگونه امکان پذیر است ... -## تفکیک نام +## Name Resolution ```{index} single: Python; Namespace (Resolution) ``` @@ -378,26 +378,26 @@ __builtins__.max == max (در prompt عبارت `import this` را تایپ کنید و به آخرین موردی که چاپ می‌شود نگاه کنید) -با این حال، ما باید بفهمیم که مفسر Python چگونه با فضاهای نام متعدد کار می‌کند. +با این حال، ما باید بفهمیم که مفسر پایتون چگونه با فضاهای نام متعدد کار می‌کند. -درک جریان اجرا به ما کمک می‌کند تا بررسی کنیم که کدام متغیرها در محدوده هستند و چگونه می‌توانیم هنگام نوشتن و اشکال‌زدایی برنامه‌ها بر روی آن‌ها عمل کنیم. +درک جریان اجرا به ما کمک می‌کند تا بررسی کنیم که کدام متغیرها در دسترس هستند و چگونه می‌توانیم هنگام نوشتن و اشکال‌زدایی برنامه‌ها با آن‌ها کار کنیم. -در هر نقطه از اجرا، در واقع حداقل دو فضای نام وجود دارند که می‌توان به طور مستقیم به آن‌ها دسترسی پیدا کرد. +در هر نقطه از اجرای برنامه، در واقع حداقل دو فضای نام وجود دارند که می‌توان به طور مستقیم به آن‌ها دسترسی داشت. ("دسترسی مستقیم" به معنای بدون استفاده از نقطه است، مانند `pi` به جای `math.pi`) -این فضاهای نام عبارتند از +این فضاهای نام عبارتند از: -* فضای نام عمومی (ماژولی که در حال اجرا است) -* فضای نام builtin +* فضای نام سراسری (ماژولی که در حال اجرا است) +* فضای نام داخلی یا builtin -اگر مفسر در حال اجرای یک تابع است، آنگاه فضاهای نام قابل دسترسی مستقیم عبارتند از +اگر مفسر در حال اجرای یک تابع باشد، آنگاه فضاهای نامی که مستقیما قابل دسترسی هستند، عبارتند از: * فضای نام محلی تابع -* فضای نام عمومی (ماژولی که در حال اجرا است) -* فضای نام builtin +* فضای نام سراسری (ماژولی که در حال اجرا است) +* فضای نام داخلی یا builtin -گاهی اوقات توابع در داخل توابع دیگر تعریف می‌شوند، مانند این +گاهی اوقات توابع در داخل توابع دیگر تعریف می‌شوند، مانند مثال زیر: ```{code-cell} python3 def f(): @@ -408,28 +408,28 @@ def f(): g() ``` -در اینجا `f` تابع *احاطه‌کننده* برای `g` است و هر تابع فضای نام خود را دارد. +در اینجا `f` تابع *بستار یا دربرگیرنده* برای `g` است و هر تابع فضای نام خود را دارد. -حالا می‌توانیم قانون نحوه کار تفکیک فضای نام را بیان کنیم: +حالا می‌توانیم قانون نحوه کار Name Resolution را در فضای نام توضیح دهیم: -ترتیبی که مفسر برای جستجوی نام‌ها دنبال می‌کند عبارت است از +ترتیبی که مفسر برای جستجوی نام‌ها دنبال می‌کند عبارت است از: 1. فضای نام محلی (اگر وجود داشته باشد) -1. سلسله مراتب فضاهای نام احاطه‌کننده (اگر وجود داشته باشند) -1. فضای نام عمومی -1. فضای نام builtin +1. زنجیره فضاهای نام توابع بستار (اگر وجود داشته باشند) +1. فضای نام سراسری +1. فضای نام داخلی یا builtin اگر نام در هیچ یک از این فضاهای نام نباشد، مفسر یک `NameError` ایجاد می‌کند. این قانون **LEGB** نامیده می‌شود (local, enclosing, global, builtin). -در اینجا مثالی آورده شده است که کمک می‌کند تا توضیح داده شود. +در ادامه یک مثال برای روشن شدن موضوع آورده شده است. -تجسم‌های اینجا توسط [nbtutor](https://github.com/lgpage/nbtutor) در یک نوت‌بوک Jupyter ایجاد شده‌اند. +تصاویر و نمودارهای این مثال توسط [nbtutor](https://github.com/lgpage/nbtutor) در یک ژوپیترنوت‌بوک ایجاد شده‌اند. -آن‌ها می‌توانند به شما کمک کنند تا برنامه خود را بهتر درک کنید وقتی که در حال یادگیری یک زبان جدید هستید. +آن‌ها می‌توانند به شما کمک کنند تا برنامه خود را بهتر درک کنید، مخصوصا زمانی که در حال یادگیری یک زبان برنامه نویسی جدید هستید. -اسکریپت `test.py` را در نظر بگیرید که به صورت زیر است +فرض کنید اسکریپتی به نام `test.py` داریم که به صورت زیر است: ```{code-cell} python3 %%file test.py @@ -449,32 +449,32 @@ print("a = ", a, "y = ", y) %run test.py ``` -ابتدا، +ابتدا: -* فضای نام عمومی `{}` ایجاد می‌شود. +* فضای نام سراسری با مقدار `{}` ایجاد می‌شود. ```{figure} /_static/lecture_specific/oop_intro/global.png ``` -* شیء تابع ایجاد می‌شود و `g` در فضای نام عمومی به آن متصل می‌شود. -* نام `a` به `0` متصل می‌شود، دوباره در فضای نام عمومی. +* یک تابع ساخته می‌شود و نام `g` در فضای نام سراسری به آن متصل می‌شود. +* نام `a`هم در فضای سراسری به مقدار `0` متصل می‌شود. ```{figure} /_static/lecture_specific/oop_intro/global2.png ``` -بعد `g` از طریق `y = g(10)` فراخوانی می‌شود که منجر به توالی زیر از اقدامات می‌شود +سپس `g` از طریق `y = g(10)` فراخوانی می‌شود که منجر به دنباله ای از اقدامات زیر می‌شود: * فضای نام محلی برای تابع ایجاد می‌شود. * نام‌های محلی `x` و `a` متصل می‌شوند، به طوری که فضای نام محلی به `{'x': 10, 'a': 1}` تبدیل می‌شود. -توجه کنید که `a` عمومی تحت تأثیر `a` محلی قرار نگرفت. +توجه کنید که فضای نام سراسری `a` تحت تأثیر فضای نام محلی `a` قرار نگرفت. ```{figure} /_static/lecture_specific/oop_intro/local1.png ``` -* دستور `x = x + a` از `a` محلی و `x` محلی برای محاسبه `x + a` استفاده می‌کند و نام محلی `x` را به نتیجه متصل می‌کند. -* این مقدار بازگردانده می‌شود و `y` در فضای نام عمومی به آن متصل می‌شود. -* `x` و `a` محلی دور انداخته می‌شوند (و فضای نام محلی آزاد می‌شود). +* دستور `x = x + a` از نام های محلی `a` و `x` برای محاسبه `x + a` استفاده می‌کند و نام محلی `x` به نتیجه آن متصل می‌کند. +* این مقدار بازگردانده می‌شود و نام `y` در فضای نام سراسری به آن متصل می‌شود. +* `x` و `a` محلی حذف می‌شوند (و فضای نام محلی آزاد می‌شود). ```{figure} /_static/lecture_specific/oop_intro/local_return.png ``` @@ -482,9 +482,9 @@ print("a = ", a, "y = ", y) (mutable_vs_immutable)= ### پارامترهای {index}`تغییرپذیر ` در مقابل {index}`تغییرناپذیر ` -این زمان خوبی است که کمی بیشتر درباره اشیاء تغییرپذیر در مقابل تغییرناپذیر صحبت کنیم. +این زمان خوبی است که کمی بیشتر درباره اشیاء تغییرپذیر و تغییرناپذیر صحبت کنیم. -بخش کد زیر را در نظر بگیرید +فرض کنید قطعه کد زیر را داریم: ```{code-cell} python3 def f(x): @@ -495,17 +495,17 @@ x = 1 print(f(x), x) ``` -اکنون می‌فهمیم که اینجا چه اتفاقی می‌افتد: کد `2` را به عنوان مقدار `f(x)` و `1` را به عنوان مقدار `x` چاپ می‌کند. +اکنون می‌فهمیم که اینجا چه اتفاقی می‌افتد: کد مقدار `2` را به عنوان خروجی `f(x)` و مقدار `1` را به عنوان مقدار `x` چاپ می‌کند. -ابتدا `f` و `x` در فضای نام عمومی ثبت می‌شوند. +ابتدا `f` و `x` در فضای نام سراسری ثبت می‌شوند. فراخوانی `f(x)` یک فضای نام محلی ایجاد می‌کند و `x` را به آن اضافه می‌کند که به `1` متصل است. -بعد، این `x` محلی به شیء عدد صحیح جدید `2` دوباره متصل می‌شود و این مقدار بازگردانده می‌شود. +سپس، این `x` محلی دوباره به شیء عدد صحیح جدید `2` متصل می‌شود و این مقدار بازگردانده می‌شود. -هیچ یک از این‌ها بر `x` عمومی تأثیر نمی‌گذارد. +هیچ یک از تغییرات، بر `x` سراسری تأثیر نمی‌گذارد. -با این حال، وقتی از یک نوع داده **تغییرپذیر** مانند لیست استفاده می‌کنیم، داستان متفاوت است +با این حال، وقتی از یک نوع داده **تغییرپذیر** مانند لیست استفاده می‌کنیم، داستان متفاوت است: ```{code-cell} python3 def f(x): @@ -516,21 +516,21 @@ x = [1] print(f(x), x) ``` -این `[2]` را به عنوان مقدار `f(x)` و *همان* را برای `x` چاپ می‌کند. +این کد `[2]` را به عنوان مقدار `f(x)` چاپ می‌کند و *همان* مقدار برای `x` سراسری هم نمایش داده می‌شود. -در اینجا چه اتفاقی می‌افتد +در اینجا چه اتفاقی می‌افتد: -* `f` به عنوان یک تابع در فضای نام عمومی ثبت می‌شود +* `f` به عنوان یک تابع در فضای نام سراسری ثبت می‌شود ```{figure} /_static/lecture_specific/oop_intro/mutable1.png ``` -* `x` به `[1]` در فضای نام عمومی متصل می‌شود +* `x` به `[1]` در فضای نام سراسری متصل می‌شود ```{figure} /_static/lecture_specific/oop_intro/mutable2.png ``` -* فراخوانی `f(x)` +* فراخوانی `f(x)`: * یک فضای نام محلی ایجاد می‌کند * `x` را به فضای نام محلی اضافه می‌کند که به `[1]` متصل است @@ -538,10 +538,10 @@ print(f(x), x) ``` ```{note} -`x` عمومی و `x` محلی به همان `[1]` اشاره می‌کنند +`x` سراسری و `x` محلی به همان لیست `[1]` اشاره می‌کنند. ``` -می‌توانیم ببینیم که هویت `x` محلی و هویت `x` عمومی یکسان است +می‌توانیم ببینیم که شناسه `x` محلی و `x` سراسری یکسان است. ```{code-cell} python3 def f(x): @@ -554,9 +554,9 @@ print(f'the identity of global x is {id(x)}') print(f(x), x) ``` -* در داخل `f(x)` +* در داخل `f(x)`: * لیست `[1]` به `[2]` تغییر می‌کند - * لیست `[2]` را برمی‌گرداند + * لیست `[2]` بازگردانده می‌شود. ```{figure} /_static/lecture_specific/oop_intro/mutable4.png ``` @@ -565,6 +565,6 @@ print(f(x), x) ```{figure} /_static/lecture_specific/oop_intro/mutable5.png ``` -اگر می‌خواهید `x` محلی و `x` عمومی را به طور جداگانه تغییر دهید، می‌توانید یک [*کپی*](https://docs.python.org/3/library/copy.html) از لیست ایجاد کنید و کپی را به `x` محلی اختصاص دهید. +اگر می‌خواهید `x` محلی و `x` سراسری را به طور جداگانه تغییر دهید، می‌توانید یک نسخه [*کپی*](https://docs.python.org/3/library/copy.html) از لیست بسازید و آن نسخه کپی را به `x` محلی اختصاص دهید. -این را برای شما برای کاوش باقی می‌گذاریم. \ No newline at end of file +این مورد را به عنوان تمرین به شما می‌سپاریم تا بررسی کنید. \ No newline at end of file