From ce6687ec4a8cee7099cadbf92782a6a1b569fe0b Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Mon, 23 Mar 2026 05:53:09 +0000 Subject: [PATCH 1/2] Update translation: lectures/python_advanced_features.md --- lectures/python_advanced_features.md | 445 +++++++++++++++++---------- 1 file changed, 277 insertions(+), 168 deletions(-) diff --git a/lectures/python_advanced_features.md b/lectures/python_advanced_features.md index 2633664..fec3078 100644 --- a/lectures/python_advanced_features.md +++ b/lectures/python_advanced_features.md @@ -8,29 +8,36 @@ kernelspec: language: python name: python3 heading-map: + More Language Features: ویژگی‌های بیشتر زبان Overview: مروری کلی - Iterables and Iterators: Iterableها و Iteratorها - Iterables and Iterators::Iterators: Iteratorها - Iterables and Iterators::Iterators in For Loops: Iteratorها در حلقه‌های For - Iterables and Iterators::Iterables: Iterableها - Iterables and Iterators::Iterators and built-ins: Iteratorها و توابع داخلی - '`*` and `**` Operators': عملگرهای `*` و `**` - '`*` and `**` Operators::Unpacking Arguments': باز کردن آرگومان‌ها - '`*` and `**` Operators::Arbitrary Arguments': آرگومان‌های دلخواه - Decorators and Descriptors: Decoratorها و Descriptorها - Decorators and Descriptors::Decorators: Decoratorها - Decorators and Descriptors::Decorators::An Example: یک مثال - Decorators and Descriptors::Decorators::Enter Decorators: Decoratorها وارد می‌شوند - Decorators and Descriptors::Descriptors: Descriptorها - Decorators and Descriptors::Descriptors::A Solution: یک راه‌حل - Decorators and Descriptors::Descriptors::How it Works: چگونه کار می‌کند - Decorators and Descriptors::Descriptors::Decorators and Properties: Decoratorها و Propertyها + Iterables and iterators: تکرارپذیرها و تکرارگرها + Iterables and iterators::Iterators: تکرارگرها + Iterables and iterators::Iterators in for loops: تکرارگرها در حلقه‌های for + Iterables and iterators::Iterables: تکرارپذیرها + Iterables and iterators::Iterators and built-ins: تکرارگرها و توابع داخلی + '`*` and `**` operators': عملگرهای `*` و `**` + '`*` and `**` operators::Unpacking arguments': باز کردن آرگومان‌ها + '`*` and `**` operators::Arbitrary arguments': آرگومان‌های دلخواه + Type hints: سرنخ‌های نوع + Type hints::Basic syntax: نحو پایه + Type hints::Common types: نوع‌های رایج + Type hints::Hints don't enforce types: سرنخ‌ها نوع‌ها را اجبار نمی‌کنند + Type hints::Why use type hints?: چرا از سرنخ‌های نوع استفاده کنیم؟ + Type hints::Type hints in scientific Python: سرنخ‌های نوع در پایتون علمی + Decorators and descriptors: دکوراتورها و توصیف‌گرها + Decorators and descriptors::Decorators: دکوراتورها + Decorators and descriptors::Decorators::An example: یک مثال + Decorators and descriptors::Decorators::Enter decorators: دکوراتورها را وارد کنید + Decorators and descriptors::Descriptors: توصیف‌گرها + Decorators and descriptors::Descriptors::A solution: یک راه‌حل + Decorators and descriptors::Descriptors::How it works: نحوه کارکرد + Decorators and descriptors::Descriptors::Decorators and properties: دکوراتورها و ویژگی‌ها Generators: Generatorها - Generators::Generator Expressions: عبارات Generator - Generators::Generator Functions: توابع Generator - Generators::Generator Functions::Example 1: مثال 1 - Generators::Generator Functions::Example 2: مثال 2 - Generators::Advantages of Iterators: مزایای Iteratorها + Generators::Generator expressions: عبارات Generator + Generators::Generator functions: توابع Generator + Generators::Generator functions::Example 1: مثال 1 + Generators::Generator functions::Example 2: مثال 2 + Generators::Advantages of iterators: مزایای Iteratorها Exercises: تمرین‌ها --- @@ -45,6 +52,17 @@ heading-map: # ویژگی‌های بیشتر زبان +(python_advanced_features)= +```{raw} jupyter +
+ + QuantEcon + +
+``` + +# ویژگی‌های بیشتر زبان + ## مروری کلی توصیه ما برای این سخنرانی آخر این است که **در مرور اول آن را رد کنید**، مگر اینکه میل شدیدی به خواندن آن داشته باشید. @@ -56,31 +74,32 @@ heading-map: موضوعات متنوعی در این سخنرانی بررسی می‌شوند، از جمله iteratorها، decoratorها و descriptorها، و generatorها. -## Iterableها و Iteratorها +## تکرارپذیرها و تکرارگرها ```{index} single: Python; Iteration ``` -ما قبلاً {ref}`چیزهایی درباره تکرار ` در Python گفته‌ایم. +ما {ref}`قبلاً چیزهایی ` درباره تکرار در پایتون گفتیم. -اکنون بیایید دقیق‌تر به نحوه کار آن نگاه کنیم، با تمرکز بر پیاده‌سازی Python از حلقه `for`. +اکنون بیایید دقیق‌تر بررسی کنیم که همه چیز چگونه کار می‌کند، با تمرکز بر پیاده‌سازی حلقه `for` در پایتون. (iterators)= -### Iteratorها + +### تکرارگرها ```{index} single: Python; Iterators ``` -Iteratorها یک رابط یکنواخت برای حرکت در عناصر یک مجموعه هستند. +تکرارگرها یک رابط یکنواخت برای پیمایش عناصر در یک مجموعه هستند. -در اینجا درباره استفاده از iteratorها صحبت خواهیم کرد --- بعداً یاد خواهیم گرفت که چگونه iteratorهای خود را بسازیم. +در اینجا درباره استفاده از تکرارگرها صحبت خواهیم کرد --- بعداً یاد خواهیم گرفت که چگونه تکرارگرهای خودمان را بسازیم. -به طور رسمی، یک *iterator* یک شیء با متد `__next__` است. +به طور رسمی، یک *تکرارگر* یک شیء با متد `__next__` است. -به عنوان مثال، اشیاء فایل iterator هستند. +به عنوان مثال، اشیاء فایل تکرارگر هستند. -برای دیدن این موضوع، بیایید دوباره به {ref}`داده‌های شهرهای آمریکا ` نگاه کنیم، -که در سلول زیر در دایرکتوری کاری فعلی نوشته شده است +برای مشاهده این موضوع، بیایید نگاهی دوباره به {ref}`داده‌های شهرهای آمریکا ` بیندازیم، +که در سلول زیر در دایرکتوری جاری نوشته می‌شود ```{code-cell} ipython %%file us_cities.txt @@ -104,16 +123,16 @@ f.__next__() f.__next__() ``` -می‌بینیم که اشیاء فایل واقعاً یک متد `__next__` دارند و فراخوانی این متد خط بعدی فایل را برمی‌گرداند. +می‌بینیم که اشیاء فایل واقعاً دارای متد `__next__` هستند و فراخوانی این متد، خط بعدی فایل را برمی‌گرداند. -متد next همچنین می‌تواند از طریق تابع داخلی `next()` قابل دسترسی باشد، +متد next همچنین از طریق تابع داخلی `next()` نیز قابل دسترسی است، که مستقیماً این متد را فراخوانی می‌کند ```{code-cell} python3 next(f) ``` -اشیاء بازگردانده شده توسط `enumerate()` نیز iterator هستند +اشیاء برگردانده‌شده توسط `enumerate()` نیز تکرارگر هستند ```{code-cell} python3 e = enumerate(['foo', 'bar']) @@ -124,9 +143,9 @@ next(e) next(e) ``` -همچنین اشیاء reader از ماژول `csv`. +همانند اشیاء reader از ماژول `csv`. -بیایید یک فایل csv کوچک بسازیم که داده‌هایی از شاخص NIKKEI را در خود دارد +بیایید یک فایل csv کوچک حاوی داده‌های شاخص NIKKEI بسازیم ```{code-cell} ipython %%file test_table.csv @@ -155,14 +174,14 @@ next(nikkei_data) next(nikkei_data) ``` -### Iteratorها در حلقه‌های For +### تکرارگرها در حلقه‌های for ```{index} single: Python; Iterators ``` -همه iteratorها می‌توانند در سمت راست کلمه کلیدی `in` در دستورات حلقه `for` قرار گیرند. +همه تکرارگرها می‌توانند در سمت راست کلیدواژه `in` در دستورات حلقه `for` قرار گیرند. -در واقع به این ترتیب است که حلقه `for` کار می‌کند: اگر بنویسیم +در واقع حلقه `for` به این شکل کار می‌کند: اگر بنویسیم ```{code-block} python3 :class: no-execute @@ -171,11 +190,11 @@ for x in iterator: ``` -آنگاه مفسر +مفسر * `iterator.___next___()` را فراخوانی می‌کند و `x` را به نتیجه متصل می‌کند * بلوک کد را اجرا می‌کند -* تکرار می‌کند تا خطای `StopIteration` رخ دهد +* تا زمانی که خطای `StopIteration` رخ دهد، تکرار می‌کند بنابراین اکنون می‌دانید که این نحو جادویی چگونه کار می‌کند @@ -187,28 +206,28 @@ for line in f: # do something ``` -مفسر فقط ادامه می‌دهد +مفسر به سادگی -1. فراخوانی `f.__next__()` و اتصال `line` به نتیجه -1. اجرای بدنه حلقه +۱. `f.__next__()` را فراخوانی می‌کند و `line` را به نتیجه متصل می‌کند +۱. بدنه حلقه را اجرا می‌کند -این کار تا زمانی که خطای `StopIteration` رخ دهد، ادامه دارد. +این تا زمانی که خطای `StopIteration` رخ دهد ادامه می‌یابد. -### Iterableها +### تکرارپذیرها ```{index} single: Python; Iterables ``` -شما از قبل می‌دانید که می‌توانیم یک لیست Python را در سمت راست `in` در یک حلقه `for` قرار دهیم +شما قبلاً می‌دانید که می‌توانیم یک لیست پایتون را در سمت راست `in` در یک حلقه `for` قرار دهیم ```{code-cell} python3 for i in ['spam', 'eggs']: print(i) ``` -پس آیا این یعنی که لیست یک iterator است؟ +پس آیا این به معنای آن است که یک لیست یک تکرارگر است؟ -جواب منفی است +پاسخ خیر است ```{code-cell} python3 x = ['foo', 'bar'] @@ -222,11 +241,11 @@ tags: [raises-exception] next(x) ``` -پس چرا می‌توانیم روی یک لیست در یک حلقه `for` تکرار کنیم؟ +پس چرا می‌توانیم در یک حلقه `for` روی یک لیست تکرار کنیم؟ -دلیل این است که یک لیست *iterable* است (در مقابل یک iterator). +دلیل این است که یک لیست *تکرارپذیر* است (در مقابل تکرارگر). -به طور رسمی، یک شیء iterable است اگر بتواند با استفاده از تابع داخلی `iter()` به یک iterator تبدیل شود. +به طور رسمی، یک شیء تکرارپذیر است اگر بتوان آن را با استفاده از تابع داخلی `iter()` به یک تکرارگر تبدیل کرد. لیست‌ها یکی از این اشیاء هستند @@ -255,9 +274,9 @@ tags: [raises-exception] next(y) ``` -بسیاری از اشیاء دیگر نیز iterable هستند، مانند دیکشنری‌ها و tupleها. +بسیاری از اشیاء دیگر نیز تکرارپذیر هستند، مانند دیکشنری‌ها و تاپل‌ها. -البته، همه اشیاء iterable نیستند +البته، نه همه اشیاء تکرارپذیر هستند ```{code-cell} python3 --- @@ -266,17 +285,17 @@ tags: [raises-exception] iter(42) ``` -برای نتیجه‌گیری از بحث ما درباره حلقه‌های `for` +برای جمع‌بندی بحث ما درباره حلقه‌های `for` -* حلقه‌های `for` روی iteratorها یا iterableها کار می‌کنند. -* در حالت دوم، iterable قبل از شروع حلقه به یک iterator تبدیل می‌شود. +* حلقه‌های `for` روی تکرارگرها یا تکرارپذیرها کار می‌کنند. +* در حالت دوم، تکرارپذیر قبل از شروع حلقه به یک تکرارگر تبدیل می‌شود. -### Iteratorها و توابع داخلی +### تکرارگرها و توابع داخلی ```{index} single: Python; Iterators ``` -برخی از توابع داخلی که روی توالی‌ها عمل می‌کنند، با iterableها نیز کار می‌کنند +برخی از توابع داخلی که روی دنباله‌ها عمل می‌کنند نیز با تکرارپذیرها کار می‌کنند * `max()`، `min()`، `sum()`، `all()`، `any()` @@ -296,7 +315,7 @@ type(y) max(y) ``` -یک نکته که باید درباره iteratorها به خاطر بسپارید این است که آن‌ها با استفاده مصرف می‌شوند +یکی از نکاتی که باید درباره تکرارگرها به خاطر سپرد این است که با استفاده تخلیه می‌شوند ```{code-cell} python3 x = [10, -10] @@ -313,18 +332,17 @@ max(y) ## عملگرهای `*` و `**` -`*` و `**` ابزارهای مناسب و پرکاربردی برای باز کردن لیست‌ها و tupleها و اجازه دادن به کاربران برای تعریف توابعی هستند که تعداد دلخواه آرگومان را به عنوان ورودی می‌گیرند. - -در این بخش، نحوه استفاده از آن‌ها و تمایز موارد استفاده آن‌ها را بررسی خواهیم کرد. +`*` و `**` ابزارهای مفید و پرکاربردی هستند که برای باز کردن (unpack) لیست‌ها و تاپل‌ها، و همچنین برای تعریف توابعی که ورودی‌های دلخواه و نامحدود می‌پذیرند، به کار می‌روند. +در این بخش، نحوه استفاده از آن‌ها را بررسی کرده و موارد استفاده آن‌ها را از یکدیگر متمایز خواهیم کرد. ### باز کردن آرگومان‌ها -وقتی روی لیستی از پارامترها عمل می‌کنیم، اغلب نیاز داریم که محتوای لیست را به عنوان آرگومان‌های منفرد به جای یک مجموعه استخراج کنیم هنگام ارسال آن‌ها به توابع. +هنگامی که روی یک لیست از پارامترها کار می‌کنیم، اغلب لازم است به جای ارسال مجموعه به عنوان یک کل، محتوای لیست را به صورت آرگومان‌های جداگانه استخراج کنیم. -خوشبختانه، عملگر `*` می‌تواند به ما کمک کند تا لیست‌ها و tupleها را به [*آرگومان‌های موضعی*](pos_args) در فراخوانی توابع باز کنیم. +خوشبختانه، عملگر `*` می‌تواند به ما کمک کند تا لیست‌ها و تاپل‌ها را در فراخوانی توابع به [*آرگومان‌های موضعی*](pos_args) تبدیل کنیم. -برای مشخص کردن مطلب، مثال‌های زیر را در نظر بگیرید: +برای روشن‌تر شدن موضوع، مثال‌های زیر را در نظر بگیرید: بدون `*`، تابع `print` یک لیست را چاپ می‌کند @@ -334,19 +352,19 @@ l1 = ['a', 'b', 'c'] print(l1) ``` -در حالی که تابع `print` عناصر منفرد را چاپ می‌کند چون `*` لیست را به آرگومان‌های منفرد باز می‌کند +در حالی که تابع `print` عناصر را به صورت جداگانه چاپ می‌کند، زیرا `*` لیست را به آرگومان‌های منفرد تبدیل می‌کند ```{code-cell} python3 print(*l1) ``` -باز کردن لیست با استفاده از `*` به آرگومان‌های موضعی معادل تعریف آن‌ها به صورت جداگانه هنگام فراخوانی تابع است +باز کردن لیست با استفاده از `*` به آرگومان‌های موضعی، معادل تعریف جداگانه آن‌ها هنگام فراخوانی تابع است ```{code-cell} python3 print('a', 'b', 'c') ``` -با این حال، عملگر `*` راحت‌تر است اگر بخواهیم دوباره از آن‌ها استفاده کنیم +با این حال، اگر بخواهیم آن‌ها را دوباره استفاده کنیم، عملگر `*` راحت‌تر است ```{code-cell} python3 l1.append('d') @@ -356,16 +374,15 @@ print(*l1) به طور مشابه، `**` برای باز کردن آرگومان‌ها استفاده می‌شود. -تفاوت این است که `**` *دیکشنری‌ها* را به *آرگومان‌های کلیدواژه‌ای* باز می‌کند. +تفاوت در این است که `**` *دیکشنری‌ها* را به *آرگومان‌های کلیدواژه‌ای* تبدیل می‌کند. -`**` اغلب زمانی استفاده می‌شود که آرگومان‌های کلیدواژه‌ای زیادی وجود دارد که می‌خواهیم دوباره استفاده کنیم. +`**` اغلب زمانی استفاده می‌شود که تعداد زیادی آرگومان کلیدواژه‌ای داریم که می‌خواهیم مجدداً از آن‌ها استفاده کنیم. -به عنوان مثال، فرض کنید می‌خواهیم چندین نمودار با استفاده از تنظیمات گرافیکی یکسان رسم کنیم، -که ممکن است شامل تنظیم مکرر بسیاری از پارامترهای گرافیکی باشد که معمولاً با استفاده از آرگومان‌های کلیدواژه‌ای تعریف می‌شوند. +به عنوان مثال، فرض کنید می‌خواهیم چندین نمودار با تنظیمات گرافیکی یکسان رسم کنیم؛ این کار ممکن است مستلزم تنظیم تکراری پارامترهای گرافیکی متعدد باشد که معمولاً با آرگومان‌های کلیدواژه‌ای تعریف می‌شوند. -در این حالت، می‌توانیم از یک دیکشنری برای ذخیره این پارامترها استفاده کنیم و از `**` برای باز کردن دیکشنری‌ها به آرگومان‌های کلیدواژه‌ای در صورت نیاز استفاده کنیم. +در این حالت، می‌توانیم از یک دیکشنری برای ذخیره این پارامترها استفاده کنیم و از `**` برای باز کردن دیکشنری‌ها به آرگومان‌های کلیدواژه‌ای هنگام نیاز بهره ببریم. -بیایید با هم یک مثال ساده را بررسی کنیم و استفاده از `*` و `**` را متمایز کنیم +بیایید با هم یک مثال ساده را مرور کرده و تفاوت کاربرد `*` و `**` را درک کنیم ```{code-cell} python3 import numpy as np @@ -418,30 +435,29 @@ generate_plots(β_0s, β_1s, 1, line_kargs, legend_kargs) plt.show() ``` -در این مثال، `*` پارامترهای zip شده `βs` و خروجی تابع `generate_data` که در tupleها ذخیره شده‌اند را باز کرد، -در حالی که `**` پارامترهای گرافیکی ذخیره شده در `legend_kargs` و `line_kargs` را باز کرد. +در این مثال، `*` پارامترهای زیپ‌شده `βs` و خروجی تابع `generate_data` ذخیره‌شده در تاپل‌ها را باز کرد، در حالی که `**` پارامترهای گرافیکی ذخیره‌شده در `legend_kargs` و `line_kargs` را باز کرد. -برای خلاصه کردن، زمانی که `*list`/`*tuple` و `**dictionary` به *فراخوانی توابع* ارسال می‌شوند، آن‌ها به آرگومان‌های منفرد به جای یک مجموعه باز می‌شوند. +به طور خلاصه، هنگامی که `*list`/`*tuple` و `**dictionary` در *فراخوانی توابع* استفاده می‌شوند، به جای مجموعه، به آرگومان‌های جداگانه تبدیل می‌شوند. -تفاوت این است که `*` لیست‌ها و tupleها را به *آرگومان‌های موضعی* باز می‌کند، در حالی که `**` دیکشنری‌ها را به *آرگومان‌های کلیدواژه‌ای* باز می‌کند. +تفاوت در این است که `*` لیست‌ها و تاپل‌ها را به *آرگومان‌های موضعی* تبدیل می‌کند، در حالی که `**` دیکشنری‌ها را به *آرگومان‌های کلیدواژه‌ای* تبدیل می‌کند. ### آرگومان‌های دلخواه -زمانی که توابع را *تعریف* می‌کنیم، گاهی مطلوب است که به کاربران اجازه دهیم هر تعداد آرگومان که می‌خواهند را وارد یک تابع کنند. +هنگامی که توابع را *تعریف* می‌کنیم، گاهی مطلوب است که به کاربران اجازه دهیم هر تعداد آرگومان که می‌خواهند به تابع بدهند. -شاید متوجه شده باشید که تابع `ax.plot()` می‌تواند تعداد دلخواهی آرگومان را مدیریت کند. +شاید متوجه شده باشید که تابع `ax.plot()` می‌تواند تعداد دلخواه آرگومان را پردازش کند. -اگر به [مستندات](https://github.com/matplotlib/matplotlib/blob/v3.6.2/lib/matplotlib/axes/_axes.py#L1417-L1669) تابع نگاه کنیم، می‌بینیم تابع به صورت زیر تعریف شده است +اگر به [مستندات](https://github.com/matplotlib/matplotlib/blob/v3.6.2/lib/matplotlib/axes/_axes.py#L1417-L1669) تابع نگاه کنیم، می‌بینیم که تابع به صورت زیر تعریف شده است ``` Axes.plot(*args, scalex=True, scaley=True, data=None, **kwargs) ``` -دوباره عملگرهای `*` و `**` را در زمینه *تعریف تابع* یافتیم. +عملگرهای `*` و `**` را دوباره در متن *تعریف تابع* مشاهده می‌کنیم. -در واقع، `*args` و `**kargs` در کتابخانه‌های علمی در Python همه جا حضور دارند تا افزونگی را کاهش دهند و ورودی‌های انعطاف‌پذیر را امکان‌پذیر کنند. +در واقع، `*args` و `**kargs` در کتابخانه‌های علمی پایتون برای کاهش تکرار و امکان ورودی‌های انعطاف‌پذیر بسیار رایج هستند. -`*args` تابع را قادر می‌سازد تا *آرگومان‌های موضعی* با اندازه متغیر را مدیریت کند +`*args` این امکان را به تابع می‌دهد که *آرگومان‌های موضعی* با تعداد متغیر را پردازش کند ```{code-cell} python3 l1 = ['a', 'b', 'c'] @@ -453,16 +469,16 @@ def arb(*ls): arb(l1, l2) ``` -ورودی‌ها به تابع ارسال شده و در یک tuple ذخیره می‌شوند. +ورودی‌ها به تابع منتقل شده و در یک تاپل ذخیره می‌شوند. -بیایید ورودی‌های بیشتری را امتحان کنیم +بیایید ورودی‌های بیشتری امتحان کنیم ```{code-cell} python3 l3 = ['z', 'x', 'b'] arb(l1, l2, l3) ``` -به طور مشابه، Python به ما اجازه می‌دهد از `**kargs` برای ارسال تعداد دلخواه *آرگومان‌های کلیدواژه‌ای* به توابع استفاده کنیم +به طور مشابه، پایتون به ما اجازه می‌دهد از `**kargs` برای ارسال تعداد دلخواه *آرگومان‌های کلیدواژه‌ای* به توابع استفاده کنیم ```{code-cell} python3 def arb(**ls): @@ -472,19 +488,121 @@ def arb(**ls): arb(l1=l1, l2=l2) ``` -می‌بینیم که Python از یک دیکشنری برای ذخیره این آرگومان‌های کلیدواژه‌ای استفاده می‌کند. +می‌بینیم که پایتون از یک دیکشنری برای ذخیره این آرگومان‌های کلیدواژه‌ای استفاده می‌کند. -بیایید ورودی‌های بیشتری را امتحان کنیم +بیایید ورودی‌های بیشتری امتحان کنیم ```{code-cell} python3 arb(l1=l1, l2=l2, l3=l3) ``` -به طور کلی، `*args` و `**kargs` هنگام *تعریف یک تابع* استفاده می‌شوند؛ آن‌ها تابع را قادر می‌سازند ورودی با اندازه دلخواه بپذیرد. +در مجموع، `*args` و `**kargs` هنگام *تعریف یک تابع* استفاده می‌شوند و به تابع امکان می‌دهند ورودی‌هایی با اندازه دلخواه بپذیرد. + +تفاوت در این است که توابع با `*args` می‌توانند *آرگومان‌های موضعی* با تعداد دلخواه بپذیرند، در حالی که `**kargs` به توابع اجازه می‌دهد تعداد دلخواه *آرگومان‌های کلیدواژه‌ای* بپذیرند. + +## سرنخ‌های نوع + +```{index} single: Python; Type Hints +``` + +پایتون یک زبان *با نوع‌گذاری پویا* است، به این معنی که نیازی به اعلان نوع متغیرها ندارید. + +(به {doc}`بحث قبلی ` ما درباره نوع‌های پویا در مقابل ایستا مراجعه کنید.) + +با این حال، پایتون از **سرنخ‌های نوع** اختیاری (که به آن‌ها حاشیه‌نویسی نوع نیز گفته می‌شود) پشتیبانی می‌کند که به شما امکان می‌دهند نوع‌های مورد انتظار متغیرها، پارامترهای تابع و مقادیر بازگشتی را مشخص کنید. + +سرنخ‌های نوع از پایتون ۳.۵ معرفی شدند و در نسخه‌های بعدی تکامل یافتند. +تمام نحو نشان داده‌شده در اینجا در پایتون ۳.۹ و بالاتر کار می‌کند. + +```{note} +سرنخ‌های نوع *در زمان اجرا توسط مفسر پایتون نادیده گرفته می‌شوند* --- آن‌ها بر نحوه اجرای کدتان تأثیری ندارند. آن‌ها صرفاً اطلاعاتی هستند و به عنوان مستندات برای انسان‌ها و ابزارها عمل می‌کنند. +``` + +### نحو پایه -تفاوت این است که توابع با `*args` قادر خواهند بود *آرگومان‌های موضعی* با اندازه دلخواه بپذیرند، در حالی که `**kargs` به توابع اجازه می‌دهد تعداد دلخواه *آرگومان‌های کلیدواژه‌ای* بپذیرند. +سرنخ‌های نوع از دونقطه `:` برای حاشیه‌نویسی متغیرها و پارامترها، و از پیکان `->` برای حاشیه‌نویسی نوع‌های بازگشتی استفاده می‌کنند. -## Decoratorها و Descriptorها +در اینجا یک مثال ساده آورده شده است: + +```{code-cell} python3 +def greet(name: str, times: int) -> str: + return (name + '! ') * times + +greet('hello', 3) +``` + +در این تعریف تابع: + +- `name: str` نشان می‌دهد که `name` انتظار می‌رود یک رشته باشد +- `times: int` نشان می‌دهد که `times` انتظار می‌رود یک عدد صحیح باشد +- `-> str` نشان می‌دهد که تابع یک رشته برمی‌گرداند + +همچنین می‌توانید متغیرها را مستقیماً حاشیه‌نویسی کنید: + +```{code-cell} python3 +x: int = 10 +y: float = 3.14 +name: str = 'Python' +``` + +### نوع‌های رایج + +پرکاربردترین سرنخ‌های نوع، نوع‌های داخلی هستند: + +| نوع | مثال | +|-----------|----------------------------------| +| `int` | `x: int = 5` | +| `float` | `x: float = 3.14` | +| `str` | `x: str = 'hello'` | +| `bool` | `x: bool = True` | +| `list` | `x: list = [1, 2, 3]` | +| `dict` | `x: dict = {'a': 1}` | + +برای ظرف‌ها، می‌توانید نوع‌های عناصرشان را مشخص کنید: + +```{code-cell} python3 +prices: list[float] = [9.99, 4.50, 2.89] +counts: dict[str, int] = {'apples': 3, 'oranges': 5} +``` + +### سرنخ‌ها نوع‌ها را اجبار نمی‌کنند + +یک نکته مهم برای برنامه‌نویسان تازه‌کار پایتون: سرنخ‌های نوع در زمان اجرا *اجباری نیستند*. + +پایتون در صورت ارسال نوع «اشتباه» خطایی صادر نمی‌کند: + +```{code-cell} python3 +def add(x: int, y: int) -> int: + return x + y + +# Passes floats — Python doesn't complain +add(1.5, 2.7) +``` + +سرنخ‌ها می‌گویند `int`، اما پایتون با خوشحالی آرگومان‌های `float` را می‌پذیرد و `4.2` را برمی‌گرداند --- که آن هم `int` نیست. + +این تفاوت کلیدی با زبان‌های با نوع‌گذاری ایستا مانند C یا Java است، که در آن‌ها عدم تطابق نوع‌ها موجب خطاهای کامپایل می‌شود. + +### چرا از سرنخ‌های نوع استفاده کنیم؟ + +اگر پایتون آن‌ها را نادیده می‌گیرد، چرا باید زحمت کشید؟ + +1. **خوانایی**: سرنخ‌های نوع امضاهای توابع را خودمستند می‌کنند. خواننده فوراً می‌داند که یک تابع چه نوع‌هایی را انتظار دارد و چه چیزی برمی‌گرداند. +2. **پشتیبانی ویرایشگر**: محیط‌های توسعه یکپارچه مانند VS Code از سرنخ‌های نوع برای ارائه تکمیل خودکار بهتر، تشخیص خطا و مستندات درخط استفاده می‌کنند. +3. **بررسی خطا**: ابزارهایی مانند [mypy](https://mypy.readthedocs.io/) و [pyrefly](https://pyrefly.org/) سرنخ‌های نوع را تحلیل می‌کنند تا اشکالات را *پیش از* اجرای کد شناسایی کنند. +4. **کد تولیدشده توسط مدل‌های زبانی بزرگ**: مدل‌های زبانی بزرگ اغلب کدی با سرنخ‌های نوع تولید می‌کنند، بنابراین درک نحو به شما کمک می‌کند خروجی آن‌ها را بخوانید و استفاده کنید. + +### سرنخ‌های نوع در پایتون علمی + +سرنخ‌های نوع به بحث {doc}`نیاز به سرعت ` مرتبط هستند: + +* کتابخانه‌های پرکارایی مانند [JAX](https://jax.readthedocs.io/) و [Numba](https://numba.pydata.org/) برای کامپایل کد ماشین سریع به دانستن نوع متغیرها متکی هستند. +* در حالی که این کتابخانه‌ها نوع‌ها را در زمان اجرا استنتاج می‌کنند نه اینکه مستقیماً سرنخ‌های نوع پایتون را بخوانند، *مفهوم* یکسان است --- اطلاعات صریح نوع، بهینه‌سازی را ممکن می‌سازد. +* با تکامل اکوسیستم پایتون، انتظار می‌رود ارتباط بین سرنخ‌های نوع و ابزارهای کارایی گسترش یابد. + +در حال حاضر، مزیت اصلی سرنخ‌های نوع در پایتون روزمره *وضوح و پشتیبانی ابزار* است، که با رشد برنامه‌ها در اندازه ارزش آن به طور فزاینده‌ای افزایش می‌یابد. + +## دکوراتورها و توصیف‌گرها ```{index} single: Python; Decorators ``` @@ -492,26 +610,26 @@ arb(l1=l1, l2=l2, l3=l3) ```{index} single: Python; Descriptors ``` -بیایید به برخی از عناصر نحوی خاص نگاه کنیم که به طور معمول توسط توسعه‌دهندگان Python استفاده می‌شوند. +بیایید به برخی عناصر نحوی خاص نگاه کنیم که به طور معمول توسط توسعه‌دهندگان پایتون استفاده می‌شوند. -ممکن است بلافاصله به مفاهیم زیر نیاز نداشته باشید، اما آن‌ها را در کد دیگران خواهید دید. +ممکن است به مفاهیم زیر بلافاصله نیاز نداشته باشید، اما آن‌ها را در کد دیگران خواهید دید. -از این رو در مرحله‌ای از آموزش Python خود باید آن‌ها را درک کنید. +از این رو در مرحله‌ای از آموزش پایتون خود باید آن‌ها را درک کنید. -### Decoratorها +### دکوراتورها ```{index} single: Python; Decorators ``` -Decoratorها کمی نحو شیرین هستند که، اگرچه به راحتی قابل اجتناب هستند، محبوب شده‌اند. +دکوراتورها نوعی قند نحوی هستند که اگرچه به راحتی می‌توان از آن‌ها اجتناب کرد، اما محبوبیت زیادی پیدا کرده‌اند. -بسیار آسان است بگوییم که decoratorها چه کاری انجام می‌دهند. +گفتن اینکه دکوراتورها چه می‌کنند بسیار آسان است. -از طرف دیگر توضیح اینکه *چرا* ممکن است از آن‌ها استفاده کنید، کمی تلاش می‌طلبد. +از طرف دیگر توضیح *چرایی* استفاده از آن‌ها نیاز به کمی تلاش دارد. #### یک مثال -فرض کنید روی برنامه‌ای کار می‌کنیم که شبیه این است +فرض کنید روی برنامه‌ای کار می‌کنیم که چیزی شبیه به این است: ```{code-cell} python3 import numpy as np @@ -525,17 +643,17 @@ def g(x): # Program continues with various calculations using f and g ``` -اکنون فرض کنید مشکلی وجود دارد: گاهی اوقات اعداد منفی به `f` و `g` در محاسباتی که دنبال می‌شود، وارد می‌شوند. +حالا فرض کنید مشکلی وجود دارد: گاهی اوقات اعداد منفی در محاسباتی که پس از این انجام می‌شوند به `f` و `g` داده می‌شوند. -اگر امتحان کنید، خواهید دید که وقتی این توابع با اعداد منفی فراخوانی می‌شوند، یک شیء NumPy به نام `nan` را برمی‌گردانند. +اگر امتحان کنید، خواهید دید که وقتی این توابع با اعداد منفی فراخوانی می‌شوند، یک شیء NumPy به نام `nan` برمی‌گردانند. -این مخفف "not a number" است (و نشان می‌دهد که شما در حال ارزیابی یک تابع ریاضی در نقطه‌ای هستید که تعریف نشده است). +این مخفف "not a number" (نه عدد) است (و نشان می‌دهد که شما سعی دارید یک تابع ریاضی را در نقطه‌ای که تعریف نشده ارزیابی کنید). -شاید این همان چیزی نیست که می‌خواهیم، زیرا مشکلات دیگری را ایجاد می‌کند که بعداً سخت قابل تشخیص هستند. +شاید این چیزی نیست که بخواهیم، زیرا مشکلات دیگری ایجاد می‌کند که بعداً سخت است کشف شوند. -فرض کنید به جای آن می‌خواهیم برنامه هر زمان که این اتفاق می‌افتد خاتمه یابد، با یک پیام خطای معقول. +فرض کنید به جای آن می‌خواهیم برنامه هر بار که این اتفاق می‌افتد با یک پیام خطای مناسب متوقف شود. -این تغییر به اندازه کافی آسان برای پیاده‌سازی است +این تغییر به اندازه کافی آسان است که پیاده‌سازی شود: ```{code-cell} python3 import numpy as np @@ -551,17 +669,17 @@ def g(x): # Program continues with various calculations using f and g ``` -با این حال متوجه شوید که اینجا کمی تکرار وجود دارد، به شکل دو خط یکسان کد. +اما توجه کنید که در اینجا تکراری وجود دارد، به شکل دو خط کد یکسان. -تکرار کد ما را طولانی‌تر و سخت‌تر برای نگهداری می‌کند، و از این رو چیزی است که سخت تلاش می‌کنیم از آن اجتناب کنیم. +تکرار کد ما را طولانی‌تر و نگهداری آن را سخت‌تر می‌کند، و از این رو چیزی است که سعی می‌کنیم از آن اجتناب کنیم. -اینجا مشکل بزرگی نیست، اما حالا تصور کنید به جای فقط `f` و `g`، ما 20 تابع داریم که باید دقیقاً به همین شکل تغییر کنیم. +در اینجا مشکل بزرگی نیست، اما حالا تصور کنید که به جای فقط `f` و `g`، 20 تابع داریم که باید دقیقاً به همان شکل تغییر دهیم. -این یعنی باید منطق تست (یعنی خط `assert` که غیرمنفی بودن را تست می‌کند) را 20 بار تکرار کنیم. +این یعنی باید منطق آزمایش (یعنی خط `assert` که عدم منفی بودن را بررسی می‌کند) را 20 بار تکرار کنیم. -وضعیت حتی بدتر است اگر منطق تست طولانی‌تر و پیچیده‌تر باشد. +وضعیت بدتر هم می‌شود اگر منطق آزمایش طولانی‌تر و پیچیده‌تر باشد. -در این نوع سناریو رویکرد زیر منظم‌تر خواهد بود +در چنین سناریویی رویکرد زیر مرتب‌تر خواهد بود: ```{code-cell} python3 import numpy as np @@ -583,41 +701,39 @@ g = check_nonneg(g) # Program continues with various calculations using f and g ``` -این پیچیده به نظر می‌رسد، پس بیایید آرام آرام روی آن کار کنیم. +این پیچیده به نظر می‌رسد پس بیایید به آرامی از آن عبور کنیم. -برای باز کردن منطق، در نظر بگیرید چه اتفاقی می‌افتد وقتی می‌گوییم `f = check_nonneg(f)`. +برای کشف منطق، در نظر بگیرید که وقتی می‌گوییم `f = check_nonneg(f)` چه اتفاقی می‌افتد. این تابع `check_nonneg` را با پارامتر `func` برابر با `f` فراخوانی می‌کند. -اکنون `check_nonneg` یک تابع جدید به نام `safe_function` ایجاد می‌کند که -`x` را به عنوان غیرمنفی تأیید می‌کند و سپس `func` را روی آن فراخوانی می‌کند (که همان `f` است). +حالا `check_nonneg` یک تابع جدید به نام `safe_function` ایجاد می‌کند که `x` را به عنوان غیرمنفی تأیید می‌کند و سپس `func` را روی آن فراخوانی می‌کند (که همان `f` است). -در نهایت، نام سراسری `f` برابر با `safe_function` قرار می‌گیرد. +در نهایت، نام سراسری `f` برابر با `safe_function` قرار داده می‌شود. -اکنون رفتار `f` همان‌طور که می‌خواهیم است، و همینطور برای `g`. +حالا رفتار `f` همان‌طور است که می‌خواهیم، و همین برای `g` نیز صدق می‌کند. -در عین حال، منطق تست فقط یک بار نوشته شده است. +در عین حال، منطق آزمایش فقط یک بار نوشته شده است. -#### Decoratorها وارد می‌شوند +#### دکوراتورها را وارد کنید ```{index} single: Python; Decorators ``` -نسخه آخر کد ما هنوز ایده‌آل نیست. +آخرین نسخه کد ما هنوز ایده‌آل نیست. -به عنوان مثال، اگر کسی کد ما را بخواند و بخواهد بداند که -`f` چگونه کار می‌کند، به دنبال تعریف تابع خواهد گشت، که این است +به عنوان مثال، اگر کسی کد ما را می‌خواند و می‌خواهد بداند `f` چطور کار می‌کند، به دنبال تعریف تابع می‌گردد که این است: ```{code-cell} python3 def f(x): return np.log(np.log(x)) ``` -ممکن است خط `f = check_nonneg(f)` را از دست بدهند. +ممکن است خط `f = check_nonneg(f)` را از دست بدهد. -به این و دلایل دیگر، decoratorها به Python معرفی شدند. +به همین دلیل و دلایل دیگر، دکوراتورها به پایتون معرفی شدند. -با decoratorها، می‌توانیم خطوط +با دکوراتورها، می‌توانیم خطوط زیر را: ```{code-cell} python3 def f(x): @@ -630,7 +746,7 @@ f = check_nonneg(f) g = check_nonneg(g) ``` -را با +با این جایگزین کنیم: ```{code-cell} python3 @check_nonneg @@ -642,33 +758,30 @@ def g(x): return np.sqrt(42 * x) ``` -جایگزین کنیم - این دو قطعه کد دقیقاً همان کار را انجام می‌دهند. -اگر همان کار را انجام می‌دهند، آیا واقعاً به نحو decorator نیاز داریم؟ +اگر همان کار را انجام می‌دهند، آیا واقعاً به نحو دکوراتور نیاز داریم؟ -خب، توجه کنید که decoratorها دقیقاً بالای تعاریف تابع قرار دارند. +خب، توجه کنید که دکوراتورها درست بالای تعریف توابع قرار می‌گیرند. -بنابراین هر کسی که به تعریف تابع نگاه می‌کند، آن‌ها را خواهد دید و از -اینکه تابع تغییر یافته است، آگاه خواهد شد. +از این رو هر کسی که به تعریف تابع نگاه می‌کند آن‌ها را می‌بیند و آگاه می‌شود که تابع تغییر یافته است. -به نظر بسیاری از افراد، این نحو decorator را به یک بهبود قابل توجه برای زبان تبدیل می‌کند. +به عقیده بسیاری از افراد، این نحو دکوراتور را به بهبودی قابل توجه در زبان تبدیل می‌کند. (descriptors)= -### Descriptorها + +### توصیف‌گرها ```{index} single: Python; Descriptors ``` -Descriptorها مشکل رایجی را در مورد مدیریت متغیرها حل می‌کنند. +توصیف‌گرها یک مشکل رایج در مدیریت متغیرها را حل می‌کنند. -برای درک موضوع، یک کلاس `Car` را در نظر بگیرید که یک ماشین را شبیه‌سازی می‌کند. +برای درک موضوع، یک کلاس `Car` را در نظر بگیرید که یک خودرو را شبیه‌سازی می‌کند. -فرض کنید این کلاس متغیرهای `miles` و `kms` را تعریف می‌کند که به ترتیب فاصله طی شده به مایل -و کیلومتر را نشان می‌دهند. +فرض کنید این کلاس متغیرهای `miles` و `kms` را تعریف می‌کند که مسافت طی‌شده را به ترتیب بر حسب مایل و کیلومتر می‌دهند. -یک نسخه بسیار ساده‌شده از کلاس ممکن است به شکل زیر باشد +یک نسخه بسیار ساده‌شده از کلاس ممکن است به شکل زیر باشد: ```{code-cell} python3 class Car: @@ -680,8 +793,7 @@ class Car: # Some other functionality, details omitted ``` -یک مشکل احتمالی که ممکن است اینجا داشته باشیم این است که کاربر یکی از این -متغیرها را تغییر دهد اما دیگری را نه +یک مشکل بالقوه‌ای که ممکن است داشته باشیم این است که کاربر یکی از این متغیرها را تغییر می‌دهد اما نه دیگری را: ```{code-cell} python3 car = Car() @@ -697,21 +809,21 @@ car.miles = 6000 car.kms ``` -در دو خط آخر می‌بینیم که `miles` و `kms` همگام نیستند. +در دو خط آخر می‌بینیم که `miles` و `kms` با هم هماهنگ نیستند. -آنچه واقعاً می‌خواهیم یک مکانیسم است که به موجب آن هر زمان که کاربر یکی از این متغیرها را تنظیم می‌کند، *دیگری به طور خودکار به‌روز شود*. +آنچه واقعاً می‌خواهیم مکانیزمی است که هر بار کاربر یکی از این متغیرها را تنظیم می‌کند، *دیگری به طور خودکار به‌روزرسانی شود*. #### یک راه‌حل -در Python، این موضوع با استفاده از *descriptorها* حل می‌شود. +در پایتون، این مشکل با استفاده از *توصیف‌گرها* حل می‌شود. -یک descriptor فقط یک شیء Python است که متدهای خاصی را پیاده‌سازی می‌کند. +یک توصیف‌گر فقط یک شیء پایتون است که متدهای خاصی را پیاده‌سازی می‌کند. -این متدها زمانی فعال می‌شوند که شیء از طریق نشانه‌گذاری ویژگی نقطه‌دار قابل دسترسی باشد. +این متدها زمانی فعال می‌شوند که از طریق نشانه‌گذاری ویژگی نقطه‌ای به شیء دسترسی پیدا می‌شود. بهترین راه برای درک این موضوع دیدن آن در عمل است. -این نسخه جایگزین از کلاس `Car` را در نظر بگیرید +این نسخه جایگزین از کلاس `Car` را در نظر بگیرید: ```{code-cell} python3 class Car: @@ -738,7 +850,7 @@ class Car: kms = property(get_kms, set_kms) ``` -ابتدا بیایید بررسی کنیم که رفتار مورد نظر را دریافت می‌کنیم +ابتدا بیایید بررسی کنیم که رفتار مطلوب را دریافت می‌کنیم: ```{code-cell} python3 car = Car() @@ -750,27 +862,25 @@ car.miles = 6000 car.kms ``` -بله، این همان چیزی است که می‌خواهیم --- `car.kms` به طور خودکار به‌روز می‌شود. +بله، این همان چیزی است که می‌خواهیم --- `car.kms` به طور خودکار به‌روزرسانی می‌شود. -#### چگونه کار می‌کند +#### نحوه کارکرد نام‌های `_miles` و `_kms` نام‌های دلخواهی هستند که برای ذخیره مقادیر متغیرها استفاده می‌کنیم. -اشیاء `miles` و `kms` *propertyها* هستند، نوع رایجی از descriptor. +اشیاء `miles` و `kms` *ویژگی‌ها* هستند، نوع رایجی از توصیف‌گر. -متدهای `get_miles`، `set_miles`، `get_kms` و `set_kms` تعریف -می‌کنند که چه اتفاقی می‌افتد وقتی این متغیرها را دریافت (یعنی دسترسی) یا تنظیم (اتصال) می‌کنید +متدهای `get_miles`، `set_miles`، `get_kms` و `set_kms` تعریف می‌کنند که وقتی این متغیرها را دریافت (یعنی دسترسی) یا تنظیم (اتصال) می‌کنید چه اتفاقی می‌افتد: -* متدهای به اصطلاح "getter" و "setter". +* اصطلاحاً متدهای "getter" و "setter". -تابع داخلی Python به نام `property` متدهای getter و setter را می‌گیرد و یک property ایجاد می‌کند. +تابع درونی پایتون `property` متدهای getter و setter را می‌گیرد و یک ویژگی ایجاد می‌کند. -به عنوان مثال، بعد از اینکه `car` به عنوان یک نمونه از `Car` ایجاد شد، شیء `car.miles` یک property است. +به عنوان مثال، پس از اینکه `car` به عنوان یک نمونه از `Car` ایجاد می‌شود، شیء `car.miles` یک ویژگی است. -به عنوان یک property، وقتی مقدار آن را از طریق `car.miles = 6000` تنظیم می‌کنیم، متد setter -آن فعال می‌شود --- در این مورد `set_miles`. +از آنجایی که یک ویژگی است، وقتی مقدار آن را از طریق `car.miles = 6000` تنظیم می‌کنیم، متد setter آن فعال می‌شود --- در این مورد `set_miles`. -#### Decoratorها و Propertyها +#### دکوراتورها و ویژگی‌ها ```{index} single: Python; Decorators ``` @@ -778,10 +888,9 @@ car.kms ```{index} single: Python; Properties ``` -این روزها بسیار رایج است که تابع `property` را از طریق یک decorator ببینید. +امروزه بسیار رایج است که تابع `property` از طریق یک دکوراتور استفاده شود. -اینجا نسخه دیگری از کلاس `Car` ما است که مانند قبل کار می‌کند اما حالا از -decoratorها برای تنظیم propertyها استفاده می‌کند +اینجا نسخه دیگری از کلاس `Car` داریم که مثل قبل کار می‌کند اما حالا از دکوراتورها برای تنظیم ویژگی‌ها استفاده می‌کند: ```{code-cell} python3 class Car: @@ -809,11 +918,12 @@ class Car: self._miles = value / 1.61 ``` -از همه جزئیات اینجا نمی‌گذریم. +در اینجا تمام جزئیات را بررسی نخواهیم کرد. -برای اطلاعات بیشتر می‌توانید به [مستندات descriptor](https://docs.python.org/3/howto/descriptor.html) مراجعه کنید. +برای اطلاعات بیشتر می‌توانید به [مستندات توصیف‌گر](https://docs.python.org/3/howto/descriptor.html) مراجعه کنید. (paf_generators)= + ## Generatorها ```{index} single: Python; Generators @@ -1084,7 +1194,6 @@ sum(draws) * نیاز به ایجاد لیست‌ها/tupleهای بزرگ را از بین می‌برند، و * یک رابط یکنواخت برای تکرار فراهم می‌کنند که می‌تواند به صورت شفاف در حلقه‌های `for` استفاده شود - ## تمرین‌ها @@ -1145,4 +1254,4 @@ for date in dates: ``` ```{solution-end} -``` \ No newline at end of file +``` From c53a5ebf0dec2216efa38347606a16f52eff63f5 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Mon, 23 Mar 2026 05:53:10 +0000 Subject: [PATCH 2/2] Update translation: .translate/state/python_advanced_features.md.yml --- .translate/state/python_advanced_features.md.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.translate/state/python_advanced_features.md.yml b/.translate/state/python_advanced_features.md.yml index 565ebad..b93f78f 100644 --- a/.translate/state/python_advanced_features.md.yml +++ b/.translate/state/python_advanced_features.md.yml @@ -1,6 +1,6 @@ -source-sha: 1a87942398e15e03539083cc944a78653c532607 -synced-at: "2026-03-20" -model: unknown -mode: RESYNC -section-count: 6 -tool-version: 0.11.0 +source-sha: f0661c5ba9339de0e8e56d2f5f1696232fedc997 +synced-at: "2026-03-23" +model: claude-sonnet-4-6 +mode: UPDATE +section-count: 7 +tool-version: 0.12.0