From 8ea8cfeedea9605717c67f125f5c9006a2e60302 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 5 Dec 2025 07:58:46 +1100 Subject: [PATCH] =?UTF-8?q?Add=20lecture:=20OOP=20I:=20=D8=A7=D8=B4=DB=8C?= =?UTF-8?q?=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 +
+ + QuantEcon + +
+``` + +# 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