From 5c74eeba5bd82af096d3d7febec0034cc5f2580d Mon Sep 17 00:00:00 2001 From: Mohammad <116789737+Mohammad222PR@users.noreply.github.com> Date: Mon, 21 Jul 2025 13:12:59 +0330 Subject: [PATCH 01/10] =?UTF-8?q?=F0=9F=8C=90=20Add=20Persian=20translatio?= =?UTF-8?q?n=20for=20`docs/fa/docs/async.md`=20(#13541)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🌐 Add Persian translation for docs/fa/docs/async.md * 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/fa/docs/async.md | 444 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 444 insertions(+) create mode 100644 docs/fa/docs/async.md diff --git a/docs/fa/docs/async.md b/docs/fa/docs/async.md new file mode 100644 index 000000000..e07374862 --- /dev/null +++ b/docs/fa/docs/async.md @@ -0,0 +1,444 @@ +# هم‌زمانی و async / await + +جزئیات در مورد سینتکس `async def` برای *توابع عملیات مسیر* و یه کم پیش‌زمینه در مورد کد ناهم‌زمان، هم‌زمانی و موازی‌سازی. + +## عجله داری؟ + +TL;DR: + +اگه از کتابخونه‌های سوم‌شخصی استفاده می‌کنی که بهت می‌گن با `await` صداشون کنی، مثل: + +```Python +results = await some_library() +``` + +اون وقت، *توابع عملیات مسیرت* رو با `async def` تعریف کن، اینجوری: + +```Python hl_lines="2" +@app.get('/') +async def read_results(): + results = await some_library() + return results +``` + +/// note + +فقط توی توابعی که با `async def` ساخته شدن می‌تونی از `await` استفاده کنی. + +/// + +--- + +اگه از یه کتابخونه سوم‌شخص استفاده می‌کنی که با یه چیزی (مثل دیتابیس، API، سیستم فایل و غیره) ارتباط داره و از `await` پشتیبانی نمی‌کنه (که الان برای بیشتر کتابخونه‌های دیتابیس اینجوریه)، اون وقت *توابع عملیات مسیرت* رو عادی، فقط با `def` تعریف کن، اینجوری: + +```Python hl_lines="2" +@app.get('/') +def results(): + results = some_library() + return results +``` + +--- + +اگه برنامه‌ات (به هر دلیلی) لازم نیست با چیز دیگه‌ای ارتباط برقرار کنه و منتظر جوابش بمونه، از `async def` استفاده کن. + +--- + +اگه نمی‌دونی چیکار کنی، از `def` معمولی استفاده کن. + +--- + +**توجه**: می‌تونی توی *توابع عملیات مسیرت* هر چقدر که لازم داری `def` و `async def` رو قاطی کنی و هر کدوم رو با بهترین گزینه برات تعریف کنی. FastAPI خودش کار درست رو باهاشون انجام می‌ده. + +به هر حال، توی هر کدوم از موقعیت‌های بالا، FastAPI هنوز ناهم‌زمان کار می‌کنه و خیلی خیلی سریع هست. + +ولی با دنبال کردن مراحل بالا، می‌تونه یه سری بهینه‌سازی عملکرد هم بکنه. + +## جزئیات فنی + +نسخه‌های مدرن پایتون از **"کد ناهم‌زمان"** با چیزی که بهش **"کروتین"** می‌گن پشتیبانی می‌کنن، با سینتکس **`async` و `await`**. + +بیاید این جمله رو تکه‌تکه توی بخش‌های زیر ببینیم: + +* **کد ناهم‌زمان** +* **`async` و `await`** +* **کروتین‌ها** + +## کد ناهم‌زمان + +کد ناهم‌زمان یعنی زبون 💬 یه راهی داره که به کامپیوتر / برنامه 🤖 بگه توی یه جای کد، باید منتظر بمونه تا *یه چیز دیگه* یه جای دیگه تموم بشه. فرض کن اون *یه چیز دیگه* اسمش "فایل-آروم" 📝 باشه. + +پس، توی اون مدت، کامپیوتر می‌تونه بره یه کار دیگه بکنه، تا وقتی "فایل-آروم" 📝 تموم بشه. + +بعدش کامپیوتر / برنامه 🤖 هر وقت فرصتی داشته باشه برمی‌گرده، چون دوباره منتظره، یا هر وقت همه کاری که اون لحظه داشته تموم کرده. و می‌بینه آیا کارایی که منتظرشون بوده تموم شدن یا نه، و هر کاری که باید بکنه رو انجام می‌ده. + +بعد، اون 🤖 اولین کاری که تموم شده (مثلاً "فایل-آروم" 📝 ما) رو برمی‌داره و هر کاری که باید باهاش بکنه رو ادامه می‌ده. + +این "منتظر یه چیز دیگه بودن" معمولاً به عملیات I/O اشاره داره که نسبتاً "آروم" هستن (نسبت به سرعت پردازنده و حافظه RAM)، مثل منتظر موندن برای: + +* داده‌هایی که از کلاینت از طریق شبکه فرستاده می‌شن +* داده‌هایی که برنامه‌ات فرستاده تا از طریق شبکه به کلاینت برسه +* محتوای یه فایل توی دیسک که سیستم بخوندش و به برنامه‌ات بده +* محتوایی که برنامه‌ات به سیستم داده تا توی دیسک بنویسه +* یه عملیات API از راه دور +* یه عملیات دیتابیس که تموم بشه +* یه کوئری دیتابیس که نتایجش برگرده +* و غیره. + +چون زمان اجرا بیشتر صرف انتظار برای عملیات I/O می‌شه، بهشون می‌گن عملیات "I/O bound". + +بهش "ناهم‌زمان" می‌گن چون کامپیوتر / برنامه لازم نیست با کار آروم "هم‌زمان" باشه، منتظر لحظه دقیق تموم شدن کار بمونه، در حالی که هیچ کاری نمی‌کنه، تا نتیجه رو بگیره و کارش رو ادامه بده. + +به جاش، چون یه سیستم "ناهم‌زمان" هست، وقتی کار تموم شد، می‌تونه یه کم توی صف منتظر بمونه (چند میکروثانیه) تا کامپیوتر / برنامه هر کاری که رفته بکنه رو تموم کنه، و بعد برگرده نتیجه رو بگیره و باهاش کار کنه. + +برای "هم‌زمان" (برخلاف "ناهم‌زمان") معمولاً از اصطلاح "ترتیبی" هم استفاده می‌کنن، چون کامپیوتر / برنامه همه مراحل رو به ترتیب دنبال می‌کنه قبل از اینکه بره سراغ یه کار دیگه، حتی اگه اون مراحل شامل انتظار باشن. + +### هم‌زمانی و برگرها + +این ایده **ناهم‌زمان** که بالا توضیح دادم گاهی بهش **"هم‌زمانی"** هم می‌گن. با **"موازی‌سازی"** فرق داره. + +**هم‌زمانی** و **موازی‌سازی** هر دو به "اتفاق افتادن چیزای مختلف کم‌وبیش همزمان" ربط دارن. + +ولی جزئیات بین *هم‌زمانی* و *موازی‌سازی* خیلی متفاوته. + +برای دیدن فرقش، این داستان در مورد برگرها رو تصور کن: + +### برگرهای هم‌زمان + +با عشقت می‌ری فست‌فود بگیرین، توی صف وایمیستی در حالی که صندوقدار سفارش آدمای جلوی تو رو می‌گیره. 😍 + + + +بعد نوبت تو می‌شه، سفارش دو تا برگر خیلی شیک برای خودت و عشقت می‌دی. 🍔🍔 + + + +صندوقدار یه چیزی به آشپز توی آشپزخونه می‌گه تا بدونن باید برگرهای تو رو آماده کنن (گرچه الان دارن برگرهای مشتریای قبلی رو درست می‌کنن). + + + +پول رو می‌دی. 💸 + +صندوقدار شماره نوبتت رو بهت می‌ده. + + + +وقتی منتظری، با عشقت می‌ری یه میز انتخاب می‌کنی، می‌شینی و کلی با عشقت حرف می‌زنی (چون برگرهات خیلی شیکن و آماده کردنشون یه کم طول می‌کشه). + +وقتی پشت میز با عشقت نشستی، در حالی که منتظر برگرهایی، می‌تونی اون زمان رو صرف تحسین این کنی که عشقت چقدر باحال، ناز و باهوشه ✨😍✨. + + + +وقتی منتظری و با عشقت حرف می‌زنی، هر از گاهی شماره‌ای که رو پیشخون نشون داده می‌شه رو چک می‌کنی که ببینی نوبتت شده یا نه. + +بعد یه جایی بالاخره نوبتت می‌شه. می‌ری پیشخون، برگرهات رو می‌گیری و برمی‌گردی سر میز. + + + +تو و عشقت برگرها رو می‌خورین و یه وقت خوب باهم دارین. ✨ + + + +/// info + +تصاویر قشنگ از کترینا تامپسون. 🎨 + +/// + +--- + +تصور کن تو توی این داستان کامپیوتر / برنامه 🤖 هستی. + +وقتی توی صف هستی، فقط بیکاری 😴، منتظر نوبتت هستی، کار خیلی "مفیدی" نمی‌کنی. ولی صف سریع پیش می‌ره چون صندوقدار فقط سفارش می‌گیره (آمادشون نمی‌کنه)، پس این خوبه. + +بعد، وقتی نوبتت می‌شه، کار "مفید" واقعی می‌کنی، منو رو پردازش می‌کنی، تصمیم می‌گیری چی می‌خوای، انتخاب عشقت رو می‌گیری، پول می‌دی، چک می‌کنی اسکناس یا کارت درست رو دادی، چک می‌کنی درست حساب شده، چک می‌کنی سفارش آیتمای درست رو داره و غیره. + +ولی بعد، گرچه هنوز برگرهات رو نداری، کارت با صندوقدار "موقتاً متوقف" ⏸ می‌شه، چون باید منتظر بمونی 🕙 تا برگرهات آماده بشن. + +ولی وقتی از پیشخون دور می‌شی و با شماره نوبتت سر میز می‌شینی، می‌تونی توجهت رو 🔀 به عشقت بدی و "کار" ⏯ 🤓 رو اون بکنی. بعدش دوباره داری یه چیز خیلی "مفید" انجام می‌دی، مثل لاس زدن با عشقت 😍. + +بعد صندوقدار 💁 با گذاشتن شماره‌ات رو نمایشگر پیشخون می‌گه "من با درست کردن برگرها تموم کردم"، ولی تو مثل دیوونه‌ها وقتی شماره‌ات رو نمایشگر میاد فوری نمی‌پری. می‌دونی کسی برگرهات رو نمی‌دزده چون شماره نوبتت رو داری، و اونا هم مال خودشون رو دارن. + +پس منتظر می‌مونی تا عشقت داستانش رو تموم کنه (کار فعلی ⏯ / وظیفه‌ای که داره پردازش می‌شه 🤓)، آروم لبخند می‌زنی و می‌گی که می‌ری برگرها رو بیاری ⏸. + +بعد می‌ری پیشخون 🔀، به کار اولیه که حالا تموم شده ⏯، برگرها رو می‌گیری، تشکر می‌کنی و می‌برشون سر میز. این مرحله / وظیفه تعامل با پیشخون رو تموم می‌کنه ⏹. این به نوبه خودش یه وظیفه جدید، "خوردن برگرها" 🔀 ⏯، می‌سازه، ولی اون قبلی که "گرفتن برگرها" بود تموم شده ⏹. + +### برگرهای موازی + +حالا فرض کن اینا "برگرهای هم‌زمان" نیستن، بلکه "برگرهای موازی" هستن. + +با عشقت می‌ری فست‌فود موازی بگیری. + +توی صف وایمیستی در حالی که چند تا (مثلاً 8 تا) صندوقدار که همزمان آشپز هم هستن سفارش آدمای جلوی تو رو می‌گیرن. + +همه قبل تو منتظرن برگرهاشون آماده بشه قبل از اینکه پیشخون رو ترک کنن، چون هر کدوم از 8 تا صندوقدار می‌ره و برگر رو همون موقع درست می‌کنه قبل از اینکه سفارش بعدی رو بگیره. + + + +بالاخره نوبت تو می‌شه، سفارش دو تا برگر خیلی شیک برای خودت و عشقت می‌دی. + +پول رو می‌دی 💸. + + + +صندوقدار می‌ره آشپزخونه. + +منتظر می‌مونی، جلوی پیشخون وایستادی 🕙، که کسی قبل از تو برگرهات رو نگیره، چون شماره نوبت نیست. + + + +چون تو و عشقت مشغول این هستین که نذارین کسی جلوتون بیاد و هر وقت برگرها رسیدن اونا رو بگیره، نمی‌تونی به عشقت توجه کنی. 😞 + +این کار "هم‌زمان" هست، تو با صندوقدار/آشپز 👨‍🍳 "هم‌زمان" هستی. باید منتظر بمونی 🕙 و درست همون لحظه که صندوقدار/آشپز 👨‍🍳 برگرها رو تموم می‌کنه و بهت می‌ده اونجا باشی، وگرنه ممکنه یکی دیگه اونا رو بگیره. + + + +بعد صندوقدار/آشپزت 👨‍🍳 بالاخره بعد از یه مدت طولانی انتظار 🕙 جلوی پیشخون با برگرهات برمی‌گرده. + + + +برگرهات رو می‌گیری و با عشقت می‌ری سر میز. + +فقط می‌خورینشون، و تمومه. ⏹ + + + +حرف زدن یا لاس زدن زیاد نبود چون بیشتر وقت صرف انتظار 🕙 جلوی پیشخون شد. 😞 + +/// info + +تصاویر قشنگ از کترینا تامپسون. 🎨 + +/// + +--- + +توی این سناریوی برگرهای موازی، تو یه کامپیوتر / برنامه 🤖 با دو تا پردازنده (تو و عشقت) هستی، هر دو منتظر 🕙 و توجهشون ⏯ رو برای مدت طولانی "انتظار جلوی پیشخون" 🕙 گذاشتن. + +فست‌فود 8 تا پردازنده (صندوقدار/آشپز) داره. در حالی که فست‌فود برگرهای هم‌زمان شاید فقط 2 تا داشته (یه صندوقدار و یه آشپز). + +ولی با این حال، تجربه نهایی بهترین نیست. 😞 + +--- + +این معادل موازی داستان برگرها بود. 🍔 + +برای یه مثال "واقعی‌تر" از زندگی، یه بانک رو تصور کن. + +تا همین چند وقت پیش، بیشتر بانک‌ها چند تا صندوقدار 👨‍💼👨‍💼👨‍💼👨‍💼 داشتن و یه صف بزرگ 🕙🕙🕙🕙🕙🕙🕙🕙. + +همه صندوقدارها کار رو با یه مشتری بعد از اون یکی 👨‍💼⏯ انجام می‌دادن. + +و باید توی صف 🕙 مدت زیادی منتظر بمونی وگرنه نوبتت رو از دست می‌دی. + +احتمالاً نمی‌خوای عشقت 😍 رو با خودت ببری بانک 🏦 برای کارای روزمره. + +### نتیجه‌گیری برگرها + +توی این سناریوی "برگرهای فست‌فود با عشقت"، چون کلی انتظار 🕙 هست، خیلی منطقی‌تره که یه سیستم هم‌زمان ⏸🔀⏯ داشته باشی. + +این برای بیشتر برنامه‌های وب هم صدق می‌کنه. + +خیلی خیلی کاربر، ولی سرورت منتظر 🕙 اتصال نه‌چندان خوبشون هست تا درخواست‌هاشون رو بفرستن. + +و بعد دوباره منتظر 🕙 که جواب‌ها برگردن. + +این "انتظار" 🕙 توی میکروثانیه‌ها اندازه‌گیری می‌شه، ولی با این حال، جمعش که بکنی آخرش کلی انتظار می‌شه. + +برای همین استفاده از کد ناهم‌زمان ⏸🔀⏯ برای APIهای وب خیلی منطقیه. + +این نوع ناهم‌زمانی چیزیه که NodeJS رو محبوب کرد (گرچه NodeJS موازی نیست) و نقطه قوت Go به‌عنوان یه زبون برنامه‌نویسیه. + +و همون سطح عملکردی هست که با **FastAPI** می‌گیری. + +و چون می‌تونی هم‌زمانی و موازی‌سازی رو همزمان داشته باشی، عملکرد بالاتری از بیشتر فریم‌ورک‌های تست‌شده NodeJS می‌گیری و هم‌تراز با Go، که یه زبون کامپایل‌شده نزدیک به C هست (همه اینا به لطف Starlette). + +### آیا هم‌زمانی از موازی‌سازی بهتره؟ + +نه! این نتیجه داستان نیست. + +هم‌زمانی با موازی‌سازی فرق داره. و توی **سناریوهای خاص** که کلی انتظار دارن بهتره. به همین خاطر، معمولاً برای توسعه برنامه‌های وب خیلی از موازی‌سازی بهتره. ولی نه برای همه‌چیز. + +برای اینکه یه تعادل بذاریم، این داستان کوتاه رو تصور کن: + +> باید یه خونه بزرگ و کثیف رو تمیز کنی. + +*آره، کل داستان همینه*. + +--- + +هیچ انتظاری 🕙 اونجا نیست، فقط کلی کار برای انجام دادن توی جاهای مختلف خونه. + +می‌تونی مثل مثال برگرها نوبت بذاری، اول پذیرایی، بعد آشپزخونه، ولی چون منتظر چیزی نیستی 🕙، فقط داری تمیز می‌کنی و تمیز می‌کنی، نوبت‌ها هیچ تأثیری نداره. + +با نوبت یا بدون نوبت (هم‌زمانی) همون قدر طول می‌کشه تا تمومش کنی و همون مقدار کار رو کردی. + +ولی توی این موقعیت، اگه بتونی اون 8 تا صندوقدار/آشپز/حالا-تمیزکار رو بیاری، و هر کدومشون (به‌علاوه خودت) یه قسمت از خونه رو تمیز کنن، می‌تونی همه کار رو **موازی** انجام بدی، با کمک اضافی، و خیلی زودتر تمومش کنی. + +توی این سناریو، هر کدوم از تمیزکارها (از جمله خودت) یه پردازنده‌ست که کار خودش رو می‌کنه. + +و چون بیشتر زمان اجرا صرف کار واقعی می‌شه (به جای انتظار)، و کار توی کامپیوتر با CPU انجام می‌شه، به این مشکلات می‌گن "CPU bound". + +--- + +مثال‌های رایج عملیات CPU bound چیزایی هستن که نیاز به پردازش ریاضی پیچیده دارن. + +مثلاً: + +* پردازش **صدا** یا **تصویر**. +* **بینایی کامپیوتری**: یه تصویر از میلیون‌ها پیکسل تشکیل شده، هر پیکسل 3 تا مقدار / رنگ داره، پردازشش معمولاً نیاز داره چیزی رو رو اون پیکسل‌ها همزمان حساب کنی. +* **یادگیری ماشین**: معمولاً کلی ضرب "ماتریس" و "بردار" لازم داره. یه جدول بزرگ پر از عدد رو تصور کن که همه‌شون رو همزمان ضرب می‌کنی. +* **یادگیری عمیق**: این یه زیرشاخه از یادگیری ماشینه، پس همون قضیه صدق می‌کنه. فقط این که یه جدول عدد برای ضرب کردن نیست، بلکه یه مجموعه بزرگ از اونا هست، و توی خیلی موارد از یه پردازنده خاص برای ساخت و / یا استفاده از این مدل‌ها استفاده می‌کنی. + +### هم‌زمانی + موازی‌سازی: وب + یادگیری ماشین + +با **FastAPI** می‌تونی از هم‌زمانی که برای توسعه وب خیلی رایجه (همون جذابیت اصلی NodeJS) استفاده کنی. + +ولی می‌تونی از فواید موازی‌سازی و چندپردازشی (اجرای چند پروسه به‌صورت موازی) برای کارای **CPU bound** مثل سیستم‌های یادگیری ماشین هم بهره ببری. + +این، به‌علاوه این واقعیت ساده که پایتون زبون اصلی برای **علم داده**، یادگیری ماشین و به‌خصوص یادگیری عمیقه، باعث می‌شه FastAPI یه انتخاب خیلی خوب برای APIها و برنامه‌های وب علم داده / یادگیری ماشین باشه (بین خیلی چیزای دیگه). + +برای دیدن اینکه چطور توی محیط واقعی به این موازی‌سازی برسی، بخش [استقرار](deployment/index.md){.internal-link target=_blank} رو ببین. + +## `async` و `await` + +نسخه‌های مدرن پایتون یه راه خیلی ساده و قابل‌فهم برای تعریف کد ناهم‌زمان دارن. این باعث می‌شه مثل کد "ترتیبی" معمولی به نظر بیاد و توی لحظه‌های درست "انتظار" رو برات انجام بده. + +وقتی یه عملیاتی هست که قبل از دادن نتیجه‌ها نیاز به انتظار داره و از این قابلیت‌های جدید پایتون پشتیبانی می‌کنه، می‌تونی اینجوری کدنویسیش کنی: + +```Python +burgers = await get_burgers(2) +``` + +نکته کلیدی اینجا `await` هست. به پایتون می‌گه که باید ⏸ منتظر بمونه تا `get_burgers(2)` کارش 🕙 تموم بشه قبل از اینکه نتیجه‌ها رو توی `burgers` ذخیره کنه. با این، پایتون می‌دونه که می‌تونه بره یه کار دیگه 🔀 ⏯ توی این مدت بکنه (مثل گرفتن یه درخواست دیگه). + +برای اینکه `await` کار کنه، باید توی یه تابع باشه که از این ناهم‌زمانی پشتیبانی کنه. برای این کار، فقط با `async def` تعریفش می‌کنی: + +```Python hl_lines="1" +async def get_burgers(number: int): + # یه سری کار ناهم‌زمان برای ساختن برگرها انجام بده + return burgers +``` + +...به جای `def`: + +```Python hl_lines="2" +# این ناهم‌زمان نیست +def get_sequential_burgers(number: int): + # یه سری کار ترتیبی برای ساختن برگرها انجام بده + return burgers +``` + +با `async def`، پایتون می‌دونه که توی اون تابع باید حواسش به عبارت‌های `await` باشه، و می‌تونه اجرای اون تابع رو "موقتاً متوقف" ⏸ کنه و بره یه کار دیگه 🔀 قبل از برگشتن بکنه. + +وقتی می‌خوای یه تابع `async def` رو صدا کنی، باید "منتظرش" بمونی. پس این کار نمی‌کنه: + +```Python +# این کار نمی‌کنه، چون get_burgers با async def تعریف شده +burgers = get_burgers(2) +``` + +--- + +پس، اگه از یه کتابخونه استفاده می‌کنی که بهت می‌گه می‌تونی با `await` صداش کنی، باید *توابع عملیات مسیرت* که ازش استفاده می‌کنن رو با `async def` بسازی، مثل: + +```Python hl_lines="2-3" +@app.get('/burgers') +async def read_burgers(): + burgers = await get_burgers(2) + return burgers +``` + +### جزئیات فنی‌تر + +شاید متوجه شده باشی که `await` فقط توی توابعی که با `async def` تعریف شدن می‌تونه استفاده بشه. + +ولی در عین حال، توابعی که با `async def` تعریف شدن باید "منتظر"شون بمونی. پس توابع با `async def` فقط توی توابعی که با `async def` تعریف شدن می‌تونن صدا زده بشن. + +حالا، قضیه مرغ و تخم‌مرغ چیه، چطور اولین تابع `async` رو صدا می‌کنی؟ + +اگه با **FastAPI** کار می‌کنی، لازم نیست نگران این باشی، چون اون "اولین" تابع، *تابع عملیات مسیرت* هست، و FastAPI می‌دونه چطور کار درست رو بکنه. + +ولی اگه بخوای بدون FastAPI از `async` / `await` استفاده کنی، اینم ممکنه. + +### کد ناهم‌زمان خودت رو بنویس + +Starlette (و **FastAPI**) بر پایه AnyIO هستن، که باعث می‌شه با کتابخونه استاندارد پایتون asyncio و Trio سازگار باشه. + +به‌خصوص، می‌تونی مستقیماً از AnyIO برای موارد استفاده پیشرفته هم‌زمانی که نیاز به الگوهای پیچیده‌تر توی کد خودت دارن استفاده کنی. + +و حتی اگه از FastAPI استفاده نکنی، می‌تونی برنامه‌های ناهم‌زمان خودت رو با AnyIO بنویسی تا خیلی سازگار باشه و فوایدش رو بگیری (مثل *هم‌زمانی ساختاریافته*). + +من یه کتابخونه دیگه روی AnyIO ساختم، یه لایه نازک روش، تا یه کم annotationهای نوع رو بهتر کنم و **تکمیل خودکار** بهتر، **خطاهای درون‌خطی** و غیره بگیرم. یه مقدمه و آموزش ساده هم داره که بهت کمک می‌کنه **بفهمی** و **کد ناهم‌زمان خودت رو بنویسی**: Asyncer. اگه بخوای **کد ناهم‌زمان رو با کد معمولی** (بلاک‌کننده/هم‌زمان) ترکیب کنی خیلی به‌دردت می‌خوره. + +### شکل‌های دیگه کد ناهم‌زمان + +این سبک استفاده از `async` و `await` توی زبون نسبتاً جدیده. + +ولی کار با کد ناهم‌زمان رو خیلی ساده‌تر می‌کنه. + +همین سینتکس (یا تقریباً یکسان) اخیراً توی نسخه‌های مدرن جاوااسکریپت (توی مرورگر و NodeJS) هم اضافه شده. + +ولی قبل از اون، مدیریت کد ناهم‌زمان خیلی پیچیده‌تر و سخت‌تر بود. + +توی نسخه‌های قبلی پایتون، می‌تونستی از نخ‌ها یا Gevent استفاده کنی. ولی کد خیلی پیچیده‌تر می‌شه برای فهمیدن، دیباگ کردن و فکر کردن بهش. + +توی نسخه‌های قبلی NodeJS / جاوااسکریپت مرورگر، از "کال‌بک‌ها" استفاده می‌کردی. که می‌رسید به جهان کال‌بک‌ها. + +## کروتین‌ها + +**کروتین** فقط یه اصطلاح خیلی شیک برای چیزیه که یه تابع `async def` برمی‌گردونه. پایتون می‌دونه که این یه چیزی مثل تابع هست، می‌تونه شروع بشه و یه جایی تموم بشه، ولی ممکنه داخلش هم موقف ⏸ بشه، هر وقت یه `await` توش باشه. + +ولی همه این قابلیت استفاده از کد ناهم‌زمان با `async` و `await` خیلی وقتا خلاصه می‌شه به استفاده از "کروتین‌ها". این قابل مقایسه با ویژگی اصلی Go، یعنی "Goroutineها" هست. + +## نتیجه‌گیری + +بیاید همون جمله از بالا رو ببینیم: + +> نسخه‌های مدرن پایتون از **"کد ناهم‌زمان"** با چیزی که بهش **"کروتین"** می‌گن پشتیبانی می‌کنن، با سینتکس **`async` و `await`**. + +حالا باید بیشتر برات معنی بده. ✨ + +همه اینا چیزیه که به FastAPI (از طریق Starlette) قدرت می‌ده و باعث می‌شه عملکرد چشمگیری داشته باشه. + +## جزئیات خیلی فنی + +/// warning + +احتمالاً می‌تونی اینو رد کنی. + +اینا جزئیات خیلی فنی از نحوه کار **FastAPI** زیر پوسته‌ست. + +اگه یه کم دانش فنی (کروتین‌ها، نخ‌ها، بلاک کردن و غیره) داری و کنجکاوی که FastAPI چطور `async def` رو در مقابل `def` معمولی مدیریت می‌کنه، ادامه بده. + +/// + +### توابع عملیات مسیر + +وقتی یه *تابع عملیات مسیر* رو با `def` معمولی به جای `async def` تعریف می‌کنی، توی یه استخر نخ خارجی اجرا می‌شه که بعدش منتظرش می‌مونن، به جای اینکه مستقیم صداش کنن (چون سرور رو بلاک می‌کنه). + +اگه از یه فریم‌ورک ناهم‌زمان دیگه میای که به روش بالا کار نمی‌کنه و عادت داری *توابع عملیات مسیر* ساده فقط محاسباتی رو با `def` معمولی برای یه سود کوچیک عملکرد (حدود 100 نانوثانیه) تعریف کنی، توجه کن که توی **FastAPI** اثرش کاملاً برعکسه. توی این موارد، بهتره از `async def` استفاده کنی مگه اینکه *توابع عملیات مسیرت* کدی داشته باشن که عملیات I/O بلاک‌کننده انجام بده. + +با این حال، توی هر دو موقعیت، احتمالش زیاده که **FastAPI** هنوز [سریع‌تر](index.md#performance){.internal-link target=_blank} از فریم‌ورک قبلی‌ات باشه (یا حداقل قابل مقایسه باهاش). + +### وابستگی‌ها + +همین برای [وابستگی‌ها](tutorial/dependencies/index.md){.internal-link target=_blank} هم صدق می‌کنه. اگه یه وابستگی یه تابع `def` معمولی به جای `async def` باشه، توی استخر نخ خارجی اجرا می‌شه. + +### زیروابستگی‌ها + +می‌تونی چند تا وابستگی و [زیروابستگی](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} داشته باشی که همدیگه رو نیاز دارن (به‌عنوان پارامترهای تعریف تابع)، بعضی‌هاشون ممکنه با `async def` ساخته بشن و بعضی‌ها با `def` معمولی. بازم کار می‌کنه، و اونایی که با `def` معمولی ساخته شدن توی یه نخ خارجی (از استخر نخ) صدا زده می‌شن به جای اینکه "منتظرشون" بمونن. + +### توابع کاربردی دیگه + +هر تابع کاربردی دیگه‌ای که مستقیم خودت صداش می‌کنی می‌تونه با `def` معمولی یا `async def` ساخته بشه و FastAPI رو نحوه صدازدنش تأثیر نمی‌ذاره. + +این برخلاف توابعی هست که FastAPI برات صداشون می‌کنه: *توابع عملیات مسیر* و وابستگی‌ها. + +اگه تابع کاربردیت یه تابع معمولی با `def` باشه، مستقیم صداش می‌کنن (همون‌طور که توی کدت نوشتی)، نه توی استخر نخ، اگه تابع با `async def` ساخته شده باشه، باید وقتی توی کدت صداش می‌کنی `await`ش کنی. + +--- + +دوباره، اینا جزئیات خیلی فنی هستن که احتمالاً اگه دنبالشون اومده باشی برات مفید باشن. + +وگرنه، با راهنمایی‌های بخش بالا باید خوب باشی: عجله داری؟. From 4ec2c0bb5b17e23916c37d891f22f71715cc284a Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 21 Jul 2025 09:43:19 +0000 Subject: [PATCH 02/10] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d33e76fce..bc15e23d4 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -9,6 +9,7 @@ hide: ### Translations +* 🌐 Add Persian translation for `docs/fa/docs/async.md`. PR [#13541](https://github.com/fastapi/fastapi/pull/13541) by [@Mohammad222PR](https://github.com/Mohammad222PR). * 🌐 Add Bangali translation for `docs/bn/about/index.md`. PR [#13882](https://github.com/fastapi/fastapi/pull/13882) by [@sajjadrahman56](https://github.com/sajjadrahman56). ### Internal From cf0c3cf2c43ef415698f3e5a083ce94386915668 Mon Sep 17 00:00:00 2001 From: Edmilson Monteiro Rodrigues Neto Date: Mon, 21 Jul 2025 10:57:31 +0100 Subject: [PATCH 03/10] =?UTF-8?q?=F0=9F=8C=90=20Update=20Portuguese=20Tran?= =?UTF-8?q?slation=20for=20`docs/pt/docs/project-generation.md`=20(#13875)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: update pt-docs project_generation.md * fix: fix typo --- docs/pt/docs/project-generation.md | 112 ++++++++--------------------- 1 file changed, 28 insertions(+), 84 deletions(-) diff --git a/docs/pt/docs/project-generation.md b/docs/pt/docs/project-generation.md index e5c935fd2..e337ad762 100644 --- a/docs/pt/docs/project-generation.md +++ b/docs/pt/docs/project-generation.md @@ -1,84 +1,28 @@ -# Geração de Projetos - Modelo - -Você pode usar um gerador de projetos para começar, por já incluir configurações iniciais, segurança, banco de dados e os primeiros _endpoints_ API já feitos para você. - -Um gerador de projetos sempre terá uma pré-configuração que você pode atualizar e adaptar para suas próprias necessidades, mas pode ser um bom ponto de partida para seu projeto. - -## Full Stack FastAPI PostgreSQL - -GitHub: https://github.com/tiangolo/full-stack-fastapi-postgresql - -### Full Stack FastAPI PostgreSQL - Recursos - -* Integração completa **Docker**. -* Modo de implantação Docker Swarm. -* Integração e otimização **Docker Compose** para desenvolvimento local. -* **Pronto para Produção** com servidor _web_ usando Uvicorn e Gunicorn. -* _Backend_ **FastAPI** Python: - * **Rápido**: Alta performance, no nível de **NodeJS** e **Go** (graças ao Starlette e Pydantic). - * **Intuitivo**: Ótimo suporte de editor. _Auto-Complete_ em todo lugar. Menos tempo _debugando_. - * **Fácil**: Projetado para ser fácil de usar e aprender. Menos tempo lendo documentações. - * **Curto**: Minimize duplicação de código. Múltiplos recursos para cada declaração de parâmetro. - * **Robusto**: Tenha código pronto para produção. Com documentação interativa automática. - * **Baseado em Padrões**: Baseado em (e completamente compatível com) padrões abertos para APIs: OpenAPI e JSON Schema. - * **Muitos outros recursos** incluindo validação automática, serialização, documentação interativa, autenticação com _tokens_ OAuth2 JWT etc. -* **Senha segura** _hashing_ por padrão. -* Autenticação **Token JWT**. -* Modelos **SQLAlchemy** (independente de extensões Flask, para que eles possam ser usados com _workers_ Celery diretamente). -* Modelos básicos para usuários (modifique e remova conforme suas necessidades). -* Migrações **Alembic**. -* **CORS** (_Cross Origin Resource Sharing_ - Compartilhamento de Recursos Entre Origens). -* _Worker_ **Celery** que pode importar e usar modelos e códigos do resto do _backend_ seletivamente. -* Testes _backend_ _REST_ baseados no **Pytest**, integrados com Docker, então você pode testar a interação completa da API, independente do banco de dados. Como roda no Docker, ele pode construir um novo repositório de dados do zero toda vez (assim você pode usar ElasticSearch, MongoDB, CouchDB, ou o que quiser, e apenas testar que a API esteja funcionando). -* Fácil integração com Python através dos **Kernels Jupyter** para desenvolvimento remoto ou no Docker com extensões como Atom Hydrogen ou Visual Studio Code Jupyter. -* _Frontend_ **Vue**: - * Gerado com Vue CLI. - * Controle de **Autenticação JWT**. - * Visualização de _login_. - * Após o _login_, visualização do painel de controle principal. - * Painel de controle principal com criação e edição de usuário. - * Edição do próprio usuário. - * **Vuex**. - * **Vue-router**. - * **Vuetify** para belos componentes _material design_. - * **TypeScript**. - * Servidor Docker baseado em **Nginx** (configurado para rodar "lindamente" com Vue-router). - * Construção multi-estágio Docker, então você não precisa salvar ou _commitar_ código compilado. - * Testes _frontend_ rodados na hora da construção (pode ser desabilitado também). - * Feito tão modular quanto possível, então ele funciona fora da caixa, mas você pode gerar novamente com Vue CLI ou criar conforme você queira, e reutilizar o que quiser. -* **PGAdmin** para banco de dados PostgreSQL, você pode modificar para usar PHPMyAdmin e MySQL facilmente. -* **Flower** para monitoração de tarefas Celery. -* Balanceamento de carga entre _frontend_ e _backend_ com **Traefik**, então você pode ter ambos sob o mesmo domínio, separados por rota, mas servidos por diferentes containers. -* Integração Traefik, incluindo geração automática de certificados **HTTPS** Let's Encrypt. -* GitLab **CI** (integração contínua), incluindo testes _frontend_ e _backend_. - -## Full Stack FastAPI Couchbase - -GitHub: https://github.com/tiangolo/full-stack-fastapi-couchbase - -⚠️ **WARNING** ⚠️ - -Se você está iniciando um novo projeto do zero, verifique as alternativas aqui. - -Por exemplo, o gerador de projetos Full Stack FastAPI PostgreSQL pode ser uma alternativa melhor, como ele é ativamente mantido e utilizado. E ele inclui todos os novos recursos e melhorias. - -Você ainda é livre para utilizar o gerador baseado em Couchbase se quiser, ele provavelmente ainda funciona bem, e você já tem um projeto gerado com ele que roda bem também (e você provavelmente já atualizou ele para encaixar nas suas necessidades). - -Você pode ler mais sobre nas documentaçãoes do repositório. - -## Full Stack FastAPI MongoDB - -...pode demorar, dependendo do meu tempo disponível e outros fatores. 😅 🎉 - -## Modelos de Aprendizado de Máquina com spaCy e FastAPI - -GitHub: https://github.com/microsoft/cookiecutter-spacy-fastapi - -### Modelos de Aprendizado de Máquina com spaCy e FastAPI - Recursos - -* Integração com modelo NER **spaCy**. -* Formato de requisição **Busca Cognitiva Azure** acoplado. -* Servidor Python _web_ **Pronto para Produção** usando Uvicorn e Gunicorn. -* Implantação **Azure DevOps** Kubernetes (AKS) CI/CD acoplada. -* **Multilingual** facilmente escolhido como uma das linguagens spaCy acopladas durante a configuração do projeto. -* **Facilmente extensível** para outros modelos de _frameworks_ (Pytorch, Tensorflow), não apenas spaCy. +# Full Stack FastAPI Template + +_Templates_, embora tipicamente venham com alguma configuração específica, são desenhados para serem flexíveis e customizáveis. Isso permite que você os modifique e adapte para as especificações do seu projeto, fazendo-os um excelente ponto de partida. 🏁 + +Você pode usar esse _template_ para começar, já que ele inclui várias configurações iniciais, segurança, banco de dados, e alguns _endpoints_ de API já feitos para você. + +Repositório GitHub: Full Stack FastAPI Template + +## Full Stack FastAPI Template - Pilha de Tecnologias e Recursos + +- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) para a API do backend em Python. + - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para as interações do Python com bancos de dados SQL (ORM). + - 🔍 [Pydantic](https://docs.pydantic.dev), usado pelo FastAPI, para validação de dados e gerenciamento de configurações. + - 💾 [PostgreSQL](https://www.postgresql.org) como banco de dados SQL. +- 🚀 [React](https://react.dev) para o frontend. + - 💃 Usando TypeScript, hooks, [Vite](https://vitejs.dev), e outras partes de uma _stack_ frontend moderna. + - 🎨 [Chakra UI](https://chakra-ui.com) para os componentes de frontend. + - 🤖 Um cliente frontend automaticamente gerado. + - 🧪 [Playwright](https://playwright.dev) para testes Ponta-a-Ponta. + - 🦇 Suporte para modo escuro. +- 🐋 [Docker Compose](https://www.docker.com) para desenvolvimento e produção. +- 🔒 _Hash_ seguro de senhas por padrão. +- 🔑 Autenticação por token JWT. +- 📫 Recuperação de senhas baseada em email. +- ✅ Testes com [Pytest](https://pytest.org). +- 📞 [Traefik](https://traefik.io) como proxy reverso / balanceador de carga. +- 🚢 Instruções de _deployment_ usando Docker Compose, incluindo como configurar um proxy frontend com Traefik para gerenciar automaticamente certificados HTTPS. +- 🏭 CI (Integração Contínua) e CD (_Deploy_ Contínuo) baseado em GitHub Actions. From d9e2aa8678c02e30613e246dc74e667cc0c27207 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 21 Jul 2025 09:57:51 +0000 Subject: [PATCH 04/10] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bc15e23d4..f3a88b4f3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -9,6 +9,7 @@ hide: ### Translations +* 🌐 Update Portuguese Translation for `docs/pt/docs/project-generation.md`. PR [#13875](https://github.com/fastapi/fastapi/pull/13875) by [@EdmilsonRodrigues](https://github.com/EdmilsonRodrigues). * 🌐 Add Persian translation for `docs/fa/docs/async.md`. PR [#13541](https://github.com/fastapi/fastapi/pull/13541) by [@Mohammad222PR](https://github.com/Mohammad222PR). * 🌐 Add Bangali translation for `docs/bn/about/index.md`. PR [#13882](https://github.com/fastapi/fastapi/pull/13882) by [@sajjadrahman56](https://github.com/sajjadrahman56). From c8f330314ee6632edf13d103d7f3f9ae2f8d42ce Mon Sep 17 00:00:00 2001 From: Mohammad <116789737+Mohammad222PR@users.noreply.github.com> Date: Mon, 21 Jul 2025 15:50:57 +0330 Subject: [PATCH 05/10] =?UTF-8?q?=F0=9F=8C=90=20Add=20Persian=20translatio?= =?UTF-8?q?n=20for=20`docs/fa/docs/python-types.md`=20(#13524)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🌐 Add Persian translation for docs/fa/docs/python-types.md * 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/fa/docs/python-types.md | 578 +++++++++++++++++++++++++++++++++++ 1 file changed, 578 insertions(+) create mode 100644 docs/fa/docs/python-types.md diff --git a/docs/fa/docs/python-types.md b/docs/fa/docs/python-types.md new file mode 100644 index 000000000..c428acbf7 --- /dev/null +++ b/docs/fa/docs/python-types.md @@ -0,0 +1,578 @@ +# مقدمه‌ای بر انواع نوع در پایتون + +پایتون از "نوع‌نما"های اختیاری (که بهشون "type hints" یا "type annotations" هم می‌گن) پشتیبانی می‌کنه. + +این **"نوع‌نماها"** یا annotationها یه سینتکس خاص هستن که بهت اجازه می‌دن نوع یه متغیر رو مشخص کنی. + +با مشخص کردن نوع متغیرها، ویرایشگرها و ابزارها می‌تونن پشتیبانی بهتری بهت بدن. + +این فقط یه **آموزش سریع / یادآوری** در مورد نوع‌نماهای پایتونه. فقط حداقل چیزایی که برای استفاده ازشون با **FastAPI** لازمه رو پوشش می‌ده... که در واقع خیلی کمه. + +**FastAPI** کاملاً بر پایه این نوع‌نماهاست و این بهش کلی مزیت و فایده می‌ده. + +ولی حتی اگه هیچ‌وقت از **FastAPI** استفاده نکنی، بازم یادگیری یه کم در موردشون به نفعته. + +/// note + +اگه حرفه‌ای پایتونی و همه‌چیز رو در مورد نوع‌نماها می‌دونی، برو سراغ فصل بعدی. + +/// + +## انگیزه + +بیاید با یه مثال ساده شروع کنیم: + +{* ../../docs_src/python_types/tutorial001.py *} + +وقتی این برنامه رو اجرا کنی، خروجی اینه: + +``` +John Doe +``` + +این تابع این کارا رو می‌کنه: + +* یه `first_name` و `last_name` می‌گیره. +* حرف اول هر کدوم رو با `title()` بزرگ می‌کنه. +* ترکیبشون می‌کنه با یه فاصله وسطشون. + +{* ../../docs_src/python_types/tutorial001.py hl[2] *} + +### ویرایشش کن + +این یه برنامه خیلی ساده‌ست. + +ولی حالا تصور کن داری از صفر می‌نویسیش. + +یه جایی شروع کردی به تعریف تابع، پارامترهات آماده‌ست... + +ولی بعد باید "اون متدی که حرف اول رو بزرگ می‌کنه" رو صدا کنی. + +آیا اسمش `upper` بود؟ یا `uppercase`؟ شاید `first_uppercase`؟ یا `capitalize`؟ + +بعد، با دوست قدیمی برنامه‌نویسا، تکمیل خودکار ویرایشگر، امتحان می‌کنی. + +پارامتر اول تابع، `first_name` رو تایپ می‌کنی، بعد یه نقطه (`.`) می‌ذاری و `Ctrl+Space` رو می‌زنی تا تکمیل خودکار بیاد. + +ولی متأسفانه، چیز مفیدی نمی‌گیری: + + + +### نوع اضافه کن + +بیا فقط یه خط از نسخه قبلی رو تغییر بدیم. + +دقیقاً این بخش، پارامترهای تابع رو، از: + +```Python + first_name, last_name +``` + +به: + +```Python + first_name: str, last_name: str +``` + +عوض می‌کنیم. + +همینه. + +اینا همون "نوع‌نماها" هستن: + +{* ../../docs_src/python_types/tutorial002.py hl[1] *} + +این با تعریف مقدار پیش‌فرض فرق داره، مثل: + +```Python + first_name="john", last_name="doe" +``` + +یه چیز متفاوته. + +ما از دونقطه (`:`) استفاده می‌کنیم، نه علامت مساوی (`=`)‌. + +و اضافه کردن نوع‌نماها معمولاً چیزی که اتفاق می‌افته رو از چیزی که بدون اونا می‌افتاد تغییر نمی‌ده. + +ولی حالا، دوباره تصور کن وسط ساختن اون تابع هستی، ولی این بار با نوع‌نماها. + +توی همون نقطه، سعی می‌کنی تکمیل خودکار رو با `Ctrl+Space` فعال کنی و اینو می‌بینی: + + + +با این، می‌تونی اسکرول کنی، گزینه‌ها رو ببینی، تا وقتی که اون چیزی که "به نظرت آشنا میاد" رو پیدا کنی: + + + +## انگیزه بیشتر + +این تابع رو چک کن، الان نوع‌نما داره: + +{* ../../docs_src/python_types/tutorial003.py hl[1] *} + +چون ویرایشگر نوع متغیرها رو می‌دونه، فقط تکمیل خودکار نمی‌گیری، بلکه چک خطاها هم داری: + + + +حالا می‌دونی که باید درستش کنی، `age` رو با `str(age)` به یه رشته تبدیل کنی: + +{* ../../docs_src/python_types/tutorial004.py hl[2] *} + +## تعریف نوع‌ها + +تازه اصلی‌ترین جا برای تعریف نوع‌نماها رو دیدی. به‌عنوان پارامترهای تابع. + +این هم اصلی‌ترین جاییه که با **FastAPI** ازشون استفاده می‌کنی. + +### نوع‌های ساده + +می‌تونی همه نوع‌های استاندارد پایتون رو تعریف کنی، نه فقط `str`. + +مثلاً می‌تونی از اینا استفاده کنی: + +* `int` +* `float` +* `bool` +* `bytes` + +{* ../../docs_src/python_types/tutorial005.py hl[1] *} + +### نوع‌های عمومی با پارامترهای نوع + +یه سری ساختار داده هستن که می‌تونن مقدارهای دیگه رو نگه دارن، مثل `dict`، `list`، `set` و `tuple`. و مقدارهای داخلیشون هم می‌تونن نوع خودشون رو داشته باشن. + +به این نوع‌ها که نوع‌های داخلی دارن می‌گن "**عمومی**" یا "generic". و می‌شه اونا رو تعریف کرد، حتی با نوع‌های داخلیشون. + +برای تعریف این نوع‌ها و نوع‌های داخلیشون، می‌تونی از ماژول استاندارد پایتون `typing` استفاده کنی. این ماژول مخصوص پشتیبانی از نوع‌نماهاست. + +#### نسخه‌های جدیدتر پایتون + +سینتکس با استفاده از `typing` با همه نسخه‌ها، از پایتون 3.6 تا جدیدترین‌ها، از جمله پایتون 3.9، 3.10 و غیره **سازگاره**. + +با پیشرفت پایتون، **نسخه‌های جدیدتر** پشتیبانی بهتری برای این نوع‌نماها دارن و توی خیلی موارد حتی لازم نیست ماژول `typing` رو وارد کنی و ازش برای تعریف نوع‌نماها استفاده کنی. + +اگه بتونی برای پروژه‌ات از یه نسخه جدیدتر پایتون استفاده کنی، می‌تونی از این سادگی اضافه بهره ببری. + +توی همه مستندات، مثال‌هایی هستن که با هر نسخه پایتون سازگارن (وقتی تفاوتی هست). + +مثلاً "**Python 3.6+**" یعنی با پایتون 3.6 یا بالاتر (مثل 3.7، 3.8، 3.9، 3.10 و غیره) سازگاره. و "**Python 3.9+**" یعنی با پایتون 3.9 یا بالاتر (مثل 3.10 و غیره) سازگاره. + +اگه بتونی از **جدیدترین نسخه‌های پایتون** استفاده کنی، از مثال‌های نسخه آخر استفاده کن، چون اونا **بهترین و ساده‌ترین سینتکس** رو دارن، مثلاً "**Python 3.10+**". + +#### لیست + +مثلاً، بیایم یه متغیر تعریف کنیم که یه `list` از `str` باشه. + +//// tab | Python 3.9+ + +متغیر رو با همون سینتکس دونقطه (`:`) تعریف کن. + +به‌عنوان نوع، `list` رو بذار. + +چون لیست یه نوعه که نوع‌های داخلی داره، اونا رو توی کروشه‌ها می‌ذاری: + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial006_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +از `typing`، `List` رو (با `L` بزرگ) وارد کن: + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial006.py!} +``` + +متغیر رو با همون سینتکس دونقطه (`:`) تعریف کن. + +به‌عنوان نوع، `List` رو که از `typing` وارد کردی بذار. + +چون لیست یه نوعه که نوع‌های داخلی داره، اونا رو توی کروشه‌ها می‌ذاری: + +```Python hl_lines="4" +{!> ../../docs_src/python_types/tutorial006.py!} +``` + +//// + +/// info + +اون نوع‌های داخلی توی کروشه‌ها بهشون "پارامترهای نوع" می‌گن. + +توی این مورد، `str` پارامتر نوعیه که به `List` (یا `list` توی پایتون 3.9 و بالاتر) پاس داده شده. + +/// + +یعنی: "متغیر `items` یه `list` هست، و هر کدوم از آیتم‌های این لیست یه `str` هستن". + +/// tip + +اگه از پایتون 3.9 یا بالاتر استفاده می‌کنی، لازم نیست `List` رو از `typing` وارد کنی، می‌تونی همون نوع معمولی `list` رو به جاش استفاده کنی. + +/// + +با این کار، ویرایشگرت حتی وقتی داری آیتم‌های لیست رو پردازش می‌کنی بهت کمک می‌کنه: + + + +بدون نوع‌ها، رسیدن به این تقریباً غیرممکنه. + +توجه کن که متغیر `item` یکی از عناصر توی لیست `items` هست. + +و با این حال، ویرایشگر می‌دونه که یه `str` هست و براش پشتیبانی می‌ده. + +#### تاپل و ست + +برای تعریف `tuple`ها و `set`ها هم همین کار رو می‌کنی: + +//// tab | Python 3.9+ + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial007_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial007.py!} +``` + +//// + +یعنی: + +* متغیر `items_t` یه `tuple` با 3 تا آیتمه، یه `int`، یه `int` دیگه، و یه `str`. +* متغیر `items_s` یه `set` هست، و هر کدوم از آیتم‌هاش از نوع `bytes` هستن. + +#### دیکشنری + +برای تعریف یه `dict`، 2 تا پارامتر نوع می‌دی، که با کاما از هم جدا شدن. + +پارامتر نوع اول برای کلیدهای `dict` هست. + +پارامتر نوع دوم برای مقدارهای `dict` هست: + +//// tab | Python 3.9+ + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial008_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial008.py!} +``` + +//// + +یعنی: + +* متغیر `prices` یه `dict` هست: + * کلیدهای این `dict` از نوع `str` هستن (مثلاً اسم هر آیتم). + * مقدارهای این `dict` از نوع `float` هستن (مثلاً قیمت هر آیتم). + +#### اتحادیه + +می‌تونی تعریف کنی که یه متغیر می‌تونه هر کدوم از **چند تا نوع** باشه، مثلاً یه `int` یا یه `str`. + +توی پایتون 3.6 و بالاتر (از جمله پایتون 3.10) می‌تونی از نوع `Union` توی `typing` استفاده کنی و نوع‌های ممکن رو توی کروشه‌ها بذاری. + +توی پایتون 3.10 یه **سینتکس جدید** هم هست که می‌تونی نوع‌های ممکن رو با یه خط عمودی (`|`) جدا کنی. + +//// tab | Python 3.10+ + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial008b_py310.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial008b.py!} +``` + +//// + +توی هر دو حالت یعنی `item` می‌تونه یه `int` یا یه `str` باشه. + +#### شاید `None` + +می‌تونی تعریف کنی که یه مقدار می‌تونه یه نوع باشه، مثلاً `str`، ولی می‌تونه `None` هم باشه. + +توی پایتون 3.6 و بالاتر (از جمله پایتون 3.10) می‌تونی با وارد کردن و استفاده از `Optional` از ماژول `typing` اینو تعریف کنی. + +```Python hl_lines="1 4" +{!../../docs_src/python_types/tutorial009.py!} +``` + +استفاده از `Optional[str]` به جای فقط `str` به ویرایشگر کمک می‌کنه خطاهایی که ممکنه فکر کنی یه مقدار همیشه `str` هست رو پیدا کنه، در حالی که می‌تونه `None` هم باشه. + +`Optional[Something]` در واقع میان‌بر برای `Union[Something, None]` هست، این دو تا معادلن. + +یعنی توی پایتون 3.10، می‌تونی از `Something | None` استفاده کنی: + +//// tab | Python 3.10+ + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial009_py310.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial009.py!} +``` + +//// + +//// tab | Python 3.8+ جایگزین + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial009b.py!} +``` + +//// + +#### استفاده از `Union` یا `Optional` + +اگه از نسخه پایتون زیر 3.10 استفاده می‌کنی، یه نکته از دید خیلی **شخصی** خودم: + +* 🚨 از `Optional[SomeType]` استفاده نکن +* به جاش ✨ **از `Union[SomeType, None]` استفاده کن** ✨. + +هر دو معادلن و زیر پوسته یکی‌ان، ولی من `Union` رو به `Optional` ترجیح می‌دم چون کلمه "**اختیاری**" انگار暗示 می‌کنه که مقدار اختیاریه، در حالی که در واقع یعنی "می‌تونه `None` باشه"، حتی اگه اختیاری نباشه و هنوز لازم باشه. + +فکر می‌کنم `Union[SomeType, None]` واضح‌تر نشون می‌ده چی معنی می‌ده. + +فقط بحث کلمات و اسم‌هاست. ولی این کلمات می‌تونن رو طرز فکر تو و تیمت نسبت به کد تأثیر بذارن. + +به‌عنوان مثال، این تابع رو ببین: + +{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *} + +پارامتر `name` به‌عنوان `Optional[str]` تعریف شده، ولی **اختیاری نیست**، نمی‌تونی تابع رو بدون پارامتر صدا کنی: + +```Python +say_hi() # اوه نه، این خطا می‌ده! 😱 +``` + +پارامتر `name` **هنوز لازمه** (نه *اختیاری*) چون مقدار پیش‌فرض نداره. با این حال، `name` مقدار `None` رو قبول می‌کنه: + +```Python +say_hi(name=None) # این کار می‌کنه، None معتبره 🎉 +``` + +خبر خوب اینه که وقتی رو پایتون 3.10 باشی، لازم نیست نگران این باشی، چون می‌تونی به‌سادگی از `|` برای تعریف اتحادیه نوع‌ها استفاده کنی: + +{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *} + +اون موقع دیگه لازم نیست نگران اسم‌هایی مثل `Optional` و `Union` باشی. 😎 + +#### نوع‌های عمومی + +این نوع‌هایی که پارامترهای نوع رو توی کروشه‌ها می‌گیرن بهشون **نوع‌های عمومی** یا **Generics** می‌گن، مثلاً: + +//// tab | Python 3.10+ + +می‌تونی از همون نوع‌های داخلی به‌عنوان نوع‌های عمومی استفاده کنی (با کروشه‌ها و نوع‌ها داخلشون): + +* `list` +* `tuple` +* `set` +* `dict` + +و همون‌طور که توی پایتون 3.8 بود، از ماژول `typing`: + +* `Union` +* `Optional` (همون‌طور که توی پایتون 3.8 بود) +* ...و بقیه. + +توی پایتون 3.10، به‌عنوان جایگزین برای استفاده از نوع‌های عمومی `Union` و `Optional`، می‌تونی از خط عمودی (`|`) برای تعریف اتحادیه نوع‌ها استفاده کنی، که خیلی بهتر و ساده‌تره. + +//// + +//// tab | Python 3.9+ + +می‌تونی از همون نوع‌های داخلی به‌عنوان نوع‌های عمومی استفاده کنی (با کروشه‌ها و نوع‌ها داخلشون): + +* `list` +* `tuple` +* `set` +* `dict` + +و همون‌طور که توی پایتون 3.8 بود، از ماژول `typing`: + +* `Union` +* `Optional` +* ...و بقیه. + +//// + +//// tab | Python 3.8+ + +* `List` +* `Tuple` +* `Set` +* `Dict` +* `Union` +* `Optional` +* ...و بقیه. + +//// + +### کلاس‌ها به‌عنوان نوع + +می‌تونی یه کلاس رو هم به‌عنوان نوع یه متغیر تعریف کنی. + +فرض کن یه کلاس `Person` داری، با یه نام: + +{* ../../docs_src/python_types/tutorial010.py hl[1:3] *} + +بعد می‌تونی یه متغیر رو از نوع `Person` تعریف کنی: + +{* ../../docs_src/python_types/tutorial010.py hl[6] *} + +و بعد، دوباره، همه پشتیبانی ویرایشگر رو داری: + + + +توجه کن که این یعنی "`one_person` یه **نمونه** از کلاس `Person` هست". + +یعنی "`one_person` خود **کلاس** به اسم `Person` نیست". + +## مدل‌های Pydantic + +Pydantic یه کتابخونه پایتونه برای اعتبارسنجی داده‌ها. + +"شکل" داده‌ها رو به‌عنوان کلاس‌هایی با ویژگی‌ها تعریف می‌کنی. + +و هر ویژگی یه نوع داره. + +بعد یه نمونه از اون کلاس رو با یه سری مقدار می‌سازی و اون مقدارها رو اعتبارسنجی می‌کنه، به نوع مناسب تبدیلشون می‌کنه (اگه لازم باشه) و یه شیء با همه داده‌ها بهت می‌ده. + +و با اون شیء نهایی همه پشتیبانی ویرایشگر رو می‌گیری. + +یه مثال از مستندات رسمی Pydantic: + +//// tab | Python 3.10+ + +```Python +{!> ../../docs_src/python_types/tutorial011_py310.py!} +``` + +//// + +//// tab | Python 3.9+ + +```Python +{!> ../../docs_src/python_types/tutorial011_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python +{!> ../../docs_src/python_types/tutorial011.py!} +``` + +//// + +/// info + +برای اطلاعات بیشتر در مورد Pydantic، مستنداتش رو چک کن. + +/// + +**FastAPI** کاملاً بر پایه Pydantic هست. + +توی [آموزش - راهنمای کاربر](tutorial/index.md){.internal-link target=_blank} خیلی بیشتر از اینا رو توی عمل می‌بینی. + +/// tip + +Pydantic یه رفتار خاص داره وقتی از `Optional` یا `Union[Something, None]` بدون مقدار پیش‌فرض استفاده می‌کنی، می‌تونی توی مستندات Pydantic در مورد فیلدهای اختیاری لازم بیشتر بخونی. + +/// + +## نوع‌نماها با Annotationهای متادیتا + +پایتون یه قابلیت هم داره که بهت اجازه می‌ده **متادیتا اضافی** رو توی این نوع‌نماها بذاری با استفاده از `Annotated`. + +//// tab | Python 3.9+ + +توی پایتون 3.9، `Annotated` بخشی از کتابخونه استاندارده، پس می‌تونی از `typing` واردش کنی. + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial013_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +توی نسخه‌های زیر پایتون 3.9، `Annotated` رو از `typing_extensions` وارد می‌کنی. + +با **FastAPI** از قبل نصب شده. + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial013.py!} +``` + +//// + +خود پایتون با این `Annotated` کاری نمی‌کنه. و برای ویرایشگرها و ابزارهای دیگه، نوع هنوز `str` هست. + +ولی می‌تونی از این فضا توی `Annotated` استفاده کنی تا به **FastAPI** متادیتای اضافی در مورد اینکه چطور می‌خوای برنامه‌ات رفتار کنه بدی. + +نکته مهم اینه که **اولین *پارامتر نوع*** که به `Annotated` می‌دی، **نوع واقعی** هست. بقیش فقط متادیتا برای ابزارهای دیگه‌ست. + +الان فقط باید بدونی که `Annotated` وجود داره، و اینکه پایتون استاندارده. 😎 + +بعداً می‌بینی که چقدر **قوی** می‌تونه باشه. + +/// tip + +اینکه این **پایتون استاندارده** یعنی هنوز **بهترین تجربه توسعه‌دهنده** رو توی ویرایشگرت، با ابزارهایی که برای تحلیل و بازسازی کدت استفاده می‌کنی و غیره می‌گیری. ✨ + +و همین‌طور کدت با خیلی از ابزارها و کتابخونه‌های دیگه پایتون خیلی سازگار می‌مونه. 🚀 + +/// + +## نوع‌نماها توی **FastAPI** + +**FastAPI** از این نوع‌نماها استفاده می‌کنه تا چند تا کار بکنه. + +با **FastAPI** پارامترها رو با نوع‌نماها تعریف می‌کنی و اینا رو می‌گیری: + +* **پشتیبانی ویرایشگر**. +* **چک نوع‌ها**. + +...و **FastAPI** از همون تعریف‌ها برای اینا استفاده می‌کنه: + +* **تعریف نیازها**: از پارامترهای مسیر درخواست، پارامترهای کوئری، هدرها، بدنه‌ها، وابستگی‌ها و غیره. +* **تبدیل داده**: از درخواست به نوع مورد نیاز. +* **اعتبارسنجی داده**: که از هر درخواست میاد: + * تولید **خطاهای خودکار** که به کلاینت برمی‌گرده وقتی داده نامعتبره. +* **مستندسازی** API با استفاده از OpenAPI: + * که بعدش توسط رابط‌های کاربری مستندات تعاملی خودکار استفاده می‌شه. + +اینا شاید همه‌ش انتزاعی به نظر بیاد. نگران نباش. همه اینا رو توی عمل توی [آموزش - راهنمای کاربر](tutorial/index.md){.internal-link target=_blank} می‌بینی. + +نکته مهم اینه که با استفاده از نوع‌های استاندارد پایتون، توی یه جا (به جای اضافه کردن کلاس‌های بیشتر، دکوراتورها و غیره)، **FastAPI** کلی از کار رو برات انجام می‌ده. + +/// info + +اگه همه آموزش رو گذروندی و برگشتی که بیشتر در مورد نوع‌ها ببینی، یه منبع خوب "تقلب‌نامه" از `mypy` هست. + +/// From 6bc29cc5ba2662cff6662a0642784530f78103f9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 21 Jul 2025 12:21:22 +0000 Subject: [PATCH 06/10] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f3a88b4f3..83c06c013 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -9,6 +9,7 @@ hide: ### Translations +* 🌐 Add Persian translation for `docs/fa/docs/python-types.md`. PR [#13524](https://github.com/fastapi/fastapi/pull/13524) by [@Mohammad222PR](https://github.com/Mohammad222PR). * 🌐 Update Portuguese Translation for `docs/pt/docs/project-generation.md`. PR [#13875](https://github.com/fastapi/fastapi/pull/13875) by [@EdmilsonRodrigues](https://github.com/EdmilsonRodrigues). * 🌐 Add Persian translation for `docs/fa/docs/async.md`. PR [#13541](https://github.com/fastapi/fastapi/pull/13541) by [@Mohammad222PR](https://github.com/Mohammad222PR). * 🌐 Add Bangali translation for `docs/bn/about/index.md`. PR [#13882](https://github.com/fastapi/fastapi/pull/13882) by [@sajjadrahman56](https://github.com/sajjadrahman56). From a5a4daa705fe4ee10d5c0eacdd3df84eb6973e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 23 Jul 2025 15:02:20 +0200 Subject: [PATCH 07/10] =?UTF-8?q?=F0=9F=94=A7=20Update=20sponsors:=20Add?= =?UTF-8?q?=20Mobb=20(#13916)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/en/data/sponsors.yml | 3 +++ docs/en/data/sponsors_badge.yml | 1 + docs/en/docs/img/sponsors/mobbai-banner.png | Bin 0 -> 3704 bytes docs/en/docs/img/sponsors/mobbai.png | Bin 0 -> 4137 bytes docs/en/overrides/main.html | 6 ++++++ 6 files changed, 11 insertions(+) create mode 100644 docs/en/docs/img/sponsors/mobbai-banner.png create mode 100644 docs/en/docs/img/sponsors/mobbai.png diff --git a/README.md b/README.md index 25a1d9179..b3eaa6b35 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ The key features are: + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index f712b6179..784fd6692 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -26,6 +26,9 @@ gold: - url: https://subtotal.com/?utm_source=fastapi&utm_medium=sponsorship&utm_campaign=open-source title: The Gold Standard in Retail Account Linking img: https://fastapi.tiangolo.com/img/sponsors/subtotal.svg + - url: https://vibe.mobb.ai/?utm_source=Fast+APi&utm_medium=Image&utm_campaign=MVS + title: Secure Your AI-Generated Code to Unlock Dev Productivity + img: https://fastapi.tiangolo.com/img/sponsors/mobbai.png silver: - url: https://databento.com/ title: Pay as you go for market data diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index d145e7372..a8895c8ed 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -43,3 +43,4 @@ logins: - permitio - LambdaTest-Inc - dribia + - madisonredtfeldt diff --git a/docs/en/docs/img/sponsors/mobbai-banner.png b/docs/en/docs/img/sponsors/mobbai-banner.png new file mode 100644 index 0000000000000000000000000000000000000000..1f59294abe86bc44f3b7535b50886191343bf4ac GIT binary patch literal 3704 zcmV-;4u|oHP)Px#AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUzK~PLoMH>+j8xaw&y2r%Q;km}tWo2w|a(RV{lO`P=ML|Vxae11e ztuQGokCvc2H8^^HhEPpXT3KJDuDV-VUs6g*m646w+0(?ry(1YJMnXk9HaNe%xApe# z>g(iWUtD^9hAAH(UszUqc5?9W>7JUFJTx+;uDXPYlcS)UeRy?cW^7PSQsw2}R8362 zy|kmE^p-}bkDAH=d()pmD4 zoVWe4|NEjj>uS3@An$F~1~Il(TDwCa?`>A2xSmpLcL?OY&1w*pwYqB{H?~=(6vMY$ zihDKF4CufxO}}j1Zaa?oTGr9fl((6tTO7I_$7x&2o4fFuuk%nT+iTAJO#lgQ_?9Ke zw$k2p;1Vf86QWmqn7n2CHI!lsPyH71*@m3No{F1w8y{I?tw@wW!h6vV?%y8BO>LGC zb|1xXy$6b~#jhY;RX~7;-Rt#V1HQf)NQ(yd)I@Fp#OO3BO#vi~lO*}@hqnhJZn&sR zJ!_U_z@IK0`c`2;Km{#UVF^T&%JK!P$FNLGqx*f`zsKFkiDdk;ZJW5WX)z7 z?zU5CO$DT_Y3OMQh>M!>N^b!aEJKLVB9NA_7j6d?kNh4oLS^r_sIw!=K-t$l{x7)>f;!;woOZyhK3sk+8Qb`%N|iKHgXWVv9cf9XKd$z=N$0 zDBq&RiR*zai;sh%rZoeY!i4T&SN0(m4GDG$O*=i6fw)V71)s?|0#pq66wRRJYuGeP zt|RM(l1)Gcd9>mSGQVR zRNAAv`k)@C)9JuX*v&xIdI%NT+Bi<>cr4R&a4-hq6g@0z)QxI|NIgS%Y>apO#qNfqeMcXOA8|8vo+fKx(C@c;{uOj(?X*(W_9=sDN1Lou!u1 z!QgVjbgu#;XEw}nspu|Q%U%TpVg>FYkGh4aa-?0wP!1OaP7PS58ed2I)|D}ac8zGV zDfL*AWguy?B74Vo1Vj}qE&~CJ)pJXm<%xYkTBKDNK{GMdK}$mLZHK5rQFUEdbGqc}Eeh4OY#@ z8!8|;lO2w?SkX9u>5$2C@kSF@f#_jk zESJmTH{d_+i!)A0GSqh*pG@HNG!@5jp5%K2>_0exm@KC?gh230^mxEP1}C|^q!y(c zTmr(2qp;-dBCCcV$XzI%XqZV0d&DIbj9L3#eG!OmLI>N_OW)vQ>K)JvpppaK=z+TI zK;CZ$PC4OeJn(CbhsH7FQJ<|U9)cBX#&Kx z9`iq^&^ReVE7khYV6_+pyydyWNA6FX7*p>ZdBJdhejD6-titJcg;-;Fv2Qv*~$$l1$6<@N7^V zW(0~B(OgIu9!Y+c65`<1h8-RyV-COZKkXD>3k48$?kkiEyeOGzC3NVee!%8>l*ExFl#e zf`ICup>-p07Dp(1;}VHg!>NN_60v5@0_lu98-p2F#-}8n%-;A!(c8mt zSK~~gx6}jgV!iufrN&d0Q?#n;Su3rz?;a#a1DyKF?0P^J<^CU*fJ|$F#0=zuP7W9d zFO0MnNUb9@KV6HzxPIksRzLy7?ql5$yMt;U;0B9oL7H}7uLr_allHBESnJ;nTKkH^ zr+S;E1Ty$z`lsPRBM`Jyj2Wy{m=+9xP8Lc7hwkM_sHDF3<61uLTo^%V5xB0$WvgQQ z!KGai-|FJl3C2Q;Kv4abjTo&(ePU0!zk>TMU3e0fTt?80Kzy@MFe(z~0IxP2z_83f zlRyl91q7l6rm99-$Vle3~0$QbeLew z70PrH()Yw~nQ2_)qd;?JKiY>23UpxXDs@Py(kjIyGKDP)5{hr-^y^kGykqE)GPhZ2bB z@5@=rlhGlacVxS^48#@+AO;qcEiT7)mQmZ?I~-usuwHCqh8Yw&qr?^})#(53}PmNyF@3_DY2J?xg~P-!vUelX;ekFv}hu zpCr#F>p+g_!=QYFKyrDODS0#my%NX+n&JgFDqF}MD^$;D z8Hnc^#u^YT9hX+zk~7w!8f5@C2As#2J_KuLc2%-;tT2ZOT*BF+!nD{ zKS8xbk^~aA$H~Q$qcqB2B=IyELnfVv5CrAtNg5xd`S>(BpRWNam5lPd+z?R$5%Y7( z05jP__vUjhozS)XLdl~(=q-T+rLJhU+vH_U4h9^msxJU3x+#H>Q!ipBnVEIsQ?f+p+$AJPmY5H{{aX}r~FGGVhS;af7wa)om5Q%V_U zLC&2gS@Lx<21EWLIXz0I$$1901p?qSIZgIXlIR~vw6hKblzbRt5#{nQtd9h4DGk*h zH4u}u9TDn`Xk=3m!aArsTG-wOwYwQ763%VX)K~_ zZysVP{VY#kjUT^=C(&20&eCV=VegxehM@Od6!zLHGxglzf5TPF^?v2|F3HV)Px#AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUz9Z*bEMH>+jMnXlz(&1%hY>$?pP)<^Xijz`GNx!|fuB@l8y2mLW zANBU{&d$hGO-%6c>9nz|rlX!RC@9+5(`{#DmXeO&-`T9Gr03}2m6DA&E-genJHEZR z$;iT#f)ZD(bOgMeRHS2iv!BN-W^ zpqzVla&U5aXklMvUR*phGRw=wm6496uDW}6bJWw$v9GBxDJzSHgHcLJU|3gQSXNtF zUz(z=q@bLYk&RMHNU^S|v9GF#gn(aJR(o}GdUkSpb#p{LJC>1-U|3dPSy#En)KW`H zQA=PVH6Zy~rX7g7|>JU}gw~khPYLR$d;vMW0zVzck?Xmj=AVyXL@KUmCDe2~6Fe zJzC2?lXNP88Rz`xzj(yPeFj-xlq_J%`7eL<>)&MWpdNhq-v76m4<`j0ZGhP`&VT#6 zfIlZ8i$X?2LLv&li~=xx{3NA7qYbbZ{QeJr{L_nIo4A3?yIqfUcY4oh@aJCN4|aNk z$87gqWw(IW0Pn?LC0`TD2yyp`x6Sy=9$^7|Bs|8C6UUjfv+I z9v=`A#2yLx;Q@U76oHSbfsX_J_m~*qsCVLaDL-+0K0oR99<9}Pmr)UK3Y_fsc<_&} z3Hc@>uM*<3ub+&+FyLa1USr^5jb3BmegdOrtZvfh*-0u-w9GLS%}~ z(>3q~oOKW5!yWkBy{8w-xnFv11>iD`&H(S5?}vxQ(UA{8ylbAWfPuFsztSG(Cr#T_ zEDr-*7z&pImx{+-!)d<2u=jNTBt6|=7Ex=gSrnP?q4gavsq3n=1sqy6i0{pTm)|&4 z0#jhQ)Ve!Jap3$Ob-Zt6x*=}wL~sX zl|cv{s>CPa9_~qcVIu}%bKt^IxEh$e5@s{DJV zyHDKA>=7VK-Qmt2@PoU_sI@%bxI22w2HuFaULkofndw#l7cdz79tbxDR zz_F>oXazPmRye2X09cbI%4&{W+plW6$_$7H}%AR*S~VQb{OW z3oQJq6vnd}K`krYm*(7*>OmL8dOoAk$^e@SOan(S(zwcATEK7kfhh>*KbX#J1blr* zU}!s)iwO$MzY`f;ycI;p*xpn(LQ13@I@BligEjQ;6QtS7J%+VmCcQEE`y^ zt74(<5e=;RR4qCl558p~>#LKv^uy!42*$eUI$Rn!R01Vg7FR#0}S2c4Puwe5x$f*0;_bfATGfJX*dGE5pZcJTn#)> z%O_e2HKEfwL5bhn@i5ujkxkN3RwB%77wNOWWDh$haIu`8n+e_=Y$p;YmPRqz#|{i) z>BizsZbBOYS8DXbrFaqw=EXW@l$NAFA{ymm=EOe5^g(3R5S7)oER`C)hB>YBPaq$4l1>L_}6J^`ZrGdR&rP%t%$>kORID>x#@h zmTzJy1TIW-f?MS&W!SNz>MGH|J=b-2bkD0}l*9TeDnj8L@F}i^;@c~gSt*o4;N);p z0Hj0zOq!@tG_Z6?a7BJ6fXfq^d8yNA3mEiSucPSZNT(vrCK8o7G{7OvBp;R7=}FR4 zPOx%XGL_};(|NKKSY(2rf|Y>lG&%+L?O316IZ1Uk5#?CsAr-JV^7LF+ezHr@nGPA03+UHkA{xVB#aEOlfh;HpqK3+!f8HNf!fSlfy{*=iI|W^BMpxtM%Z z?-?|(a(Z<{i7qHrVTWB=9{8B^Vqh=>2de>Bg~C~24ppb}jqfu|u!9nV^BY8{0Qh!6 zc)|(Nqsm|ExvnE29_#cZ(dYYQpe+$)3@Z!szz`Wtj{j8zj6KHS_}^4YEpKHgoB>Xj z?X0UzYl3OY9V>H~gjU{;*}ytI`9aqKOOr27@7R^)fKwB`1Pm7wYgwuVt_~b>z_~Xq zK=mKf>hv=7d14Hg);0~Cr~{*d45xZ8O#sTAXCBy$+`WOT0|y(JWmTGplnyoD(oq97 zP9S8LImIiLc+|kU@6tJUDQ9h_viCXQz?5DBej`=-JDnh_k?K%5JBPh==7G4LcWJB` zJn`H#7)N(M?ejWdY5uI$o620C4V>=BUINAiZ3UxMuhA(m3|9Ik8Z_|0H-k#;5sn40 zXC)u2fjz(XokP(gn!aHcXd zhc9b@@#R{w0&qPhEu+$cbSC!VwqVyp6FSZFgr>k>{jexV2^|?rL4$6Qt z7STGc{<%qQ;E)4ObC0o_q4LeVE5iZdWVsQQ_EzK(gMC%70kHC=Wo4poMV_)8IB-=n z8Uxn`4oko?_h_$n%uXj}GlvDq#~QIKV=LcXFLj}C5%5o08fo-80XNd-O1bHQzG| zU;E~UC`fmk9LNw~DHwXrrsp1wo zkA=8x62pAd;B!VIlcJ|G)gu~@TU30Lnm7mnm!g>(+ zVM&VO*^aZ(1h`2koCU@)#i9BJ+r!fBHz}~p@dPS;Dds?5Dma!w;1^bIGGOT&CA4m? z<}8orMlN-_kwv%qKssx5I0Ta9G1aLMtnIB=D_bwaZ26nd8h&2j@bHEgL zCZm-JxUY7P)&oNqZHpfU=s9fVCVewmF$?JGyf-a*S=?}t3XNDpKROF6-ijd1K9{*U z3A`gmrUV$wRyPm{Jzp9zvrY*!CSNWdBciL9qm!aH>g5)zka?^0-r0Og=2cZ$x8bkO zKFFpECYgy*#N{{F5mg4~GwX;yCT8q?T&px)F4DcN+R#wRFV%TwrGalX! zk6Po~Tc<@fIzWF$oT1Yi4~L7+Cvr1;D!}(vXfOgJa!VFlTh3^DOE%8PoQy`(aqEms zN5t9Kbf)uNGIE{>@ck_ogu@Onewt5V5gtJYIt~$*;fx$PWOFp#n2yHszngk&Sn?ni zi;$Zs8Il_^U%*OCc5lcT84aNuV1aVT59H$~GMbT5`)L3#?#=}o$HP>6Q^6w@M+B9ds{3JFu=Rl}{ z(%E%3u1A|Uw_9`cvB&ccm