<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های GreatBahram</title>
        <link>https://virgool.io/feed/@GreatBahram</link>
        <description>Pythonista, Free Software Enthusiast. GNU/Linux Master. Network Security Researcher. Son. Brother.</description>
        <language>fa</language>
        <pubDate>2026-06-07 12:32:13</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/6637/avatar/dJuDdb.png?height=120&amp;width=120</url>
            <title>GreatBahram</title>
            <link>https://virgool.io/@GreatBahram</link>
        </image>

                    <item>
                <title>معرفی کتاب - Grokking Algorithms</title>
                <link>https://virgool.io/@GreatBahram/%D9%85%D8%B9%D8%B1%D9%81%DB%8C-%DA%A9%D8%AA%D8%A7%D8%A8-grokking-algorithms-pzkepwtlytys</link>
                <description>عنوان کتاب: درک الگوریتم‌ها، راهنمایی مصور برای برنامه‌نویسان و دیگر افراد کنجکاو 🙃سلاممن کتاب Grokking Algorithms از Aditya Y Bhargava رو چند وقت پیش خوندم خواستم نظرم رو راجع‌به اش بنویسم. اول از همه خیلی کتاب ساده ای هست اگر قبلا این مطالب رو توی دانشگاه یا جای دیگه یاد گرفتی، اینجا فرصت خوبی هست که خیلی سریع روی موضوع‌ها مرور کنی. اما اگر دنبال اینی که تمرین های باحال داشته باشی و توی جزئیات مساله‌ها بری شاید این بهترین انتخاب نباشه.هدف کتاب یا بهتر بگم چیزی که نویسنده کلا براش معروف هست اینه که مسائل پیچیده رو با کمک تصویر درکشون رو برای مخاطب ساده تر کنه و این مزیت باحال داره که اینجا میخوام یه مثال راجع‌به اش بزنم. آدیتا (نویسنده کتاب) یجا در رابطه با جستجوی باینری صحبت میکنه و اینکه چرا این الگوریتم روی لیست پیوندی linked-list جواب نمیده و از طرف دیگه چرا linked-list جذاب میتونه باشه. یه کوچولو که جلوتر رفت گفتش که حالا فرض کنید یه آرایه مرتب شده داریم می‌خوایم یه عنصر جدید رو داخل آرایه مرتب شده بذاریم، خب اول نیاز داریم جاش رو پیدا کنیم که با جستجوی باینری این کار خیلی راحته اما چون آرایه است نیاز به جابجای داره که دیگه همه چی خراب میشه ولی اگر میشد link-list باشه چی میشد پسر، نه؟ بعد شروع می‌کنه راجع‌به Binary Search Tree ها صحبت می‌کنه که چطور BST ها مزیت‌ جستجوی باینری آرایه رو بعلاوه هزینه پایین اضافه کردن linked-list رو به ما میده و اینکه یه سری‌هاشون می‌تونن خودشون رو بالانس 🤹 نگه دارن و چرا بالانس بودن مهمه. این رو گفتم که به این نتیجه برسم وقتی روی کلیت موضوع صحبت می‌کنیم بعضی اوقات به دید می‌رسیم که اگر به جزئیات بپردازیم شاید راحت نتونیم بهش برسیم و این شاید جالب‌ترین نکته این کتاب برای من بود.در پایان، این کتاب رو خیلی راحت‌ میشه خوند، من وبلاگ آدیتا رو معمولا دنبال می‌کنم و دوست داشتم کتاب‌ش رو هم یه نگاه بندازم که خیلی ازم زمانی هم نگرفت و این موضوع‌های الگوریتمی هم هر بار که یه چیز جدید راجع بهشون یاد میگیری به لبخند روی لب آدم میاره پس چرا شما هم این کتاب رو نخونی؟از اینجا کجا برم؟لینک به کتابآدیتا وبلاگ</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Mon, 08 Dec 2025 09:55:47 +0330</pubDate>
            </item>
                    <item>
                <title>بریم یوتیوب؟</title>
                <link>https://virgool.io/@GreatBahram/youtube-i-am-coming-wjux5lqzu5t0</link>
                <description>Join me on YouTube Imageسلام به همه دوستای ویرگولی!!من خیلی وقت هست اینجا مطلبی ننوشتم و دلایل این کار کم نیستن اما به جای اینکه که به اون دلایل بپردازم خواستم بگم این روزا دوست دارم یکم ویدیو بسازم چون ساخت‌اش، از دور حداقل، یکم راحت‌تر از نوشتن هست و دوست دارم این روش رو هم یه تستی کرده باشم.با خودم داشتم فکر میکردم که راجعبه چی ویدیو بسازم گفتم به جای اینکه اول کاری خیلی بشینم به سرفصل و محتوا فکر کنم با هم یه کتابی که من دوست دارم رو بخونیم شاید چیز جالبی از توش دراومد (who knows)؟خب چه کتابی؟ من خیلی وقت دوست داشتم راجعبه سیستم type annotation توی پایتون مطلب بنویسم اما فرصت نمیشد؛ یه مقداری هم درگیر مسائل search, path finding شده بودم دیدم این کتاب Classic Computer Science in Python خیلی خوب نوشته شده چخوب میشه اینارو با بشینیم بخونیم. این کتاب چند تا نقطه قوت خوب داره:راجعبه مسائل خیلی جالبی حرف میزنه از سرچ‌های ساده شروع میکنه تا به a_stra میرسه، بعدش سری به Constraint Satisfaction Problem میزنه، بعد وارد موضوع های جالبی مثل clustering و شبکه‌ی عصبی! میشه. من با خودم فکر کردم خب اینا که برای همه ما کاربردی هست، مرورشون یا بعضاً یادگیری‌شون هم چیز قشنگی میتونه بشه؟کیفیت کدهای پایتونی که زده خیلی خوبه، خیلی خوب مسائل رو مدل کرده و این خودش مثل این هست که با هم داریم سورس کد یه پروژه رو میخونیم.از طرفی هم کتاب اومده خیلی type hint های خوبی استفاده کرده، یه جورایی اینجا تقریباً با خیلی از پیچیدگی‌های type hint اشنا میشم.همین سه تا دلیل برای من کافی بودن که استارت این کار رو بزنم و (besides we have nothing to lose) خب چرا استارت نزنیم؟فقط چون شروع کار هست انتظار بهترین کیفیت کار رو از من نداشته باشید من با حداقل امکانات ? دارم استارت میزنم و واقعاً خیلی کار ادیت ویدیو بلد نیستم توی این مسیر هر سری یه چیزی رو دارم یاد میگیرم؛ اما خیلی چیزهای جالبی هست که دوست دارم با هم یاد بگیریم. هم این ویرگول و هم این ویدیو بیشتر چیزهایی هستن که یاد گرفتم و دوست داشتم یه جوری به بقیه هم انتقال بدم (as they say sharing is caring).خب اگر دوست داشتید ادامه مسیر رو با من باشید توی یوتیوب پایین می‌تونید من رو دنبال کنید و سعی می‌کنم هر موقع موضوع جدیدی رو شروع کردم اینجا بگم که کسی مطالب رو از دست نده:لینک کانال یوتیوبلینک پلی‌لیست مخصوص این کتاباما موضوعاتی که میخوام راجعبه‌اش ویدیو بسازم، من فکر مفاهیم بنیادی پایتون رو اینجا تا جای خوبی با هم پوشش دادیم از اینجا به بعد میتونیم توی مسیرهای هیجان انگیز خوبی پا بذاریم؟ (Like what? wait for it).بریم ببنیم یوتیوب چه حرفی برای گفتن داره! تا بعد خدانگهدار ?</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Fri, 10 Sep 2021 15:26:14 +0430</pubDate>
            </item>
                    <item>
                <title>آنچه می‌بینید و آنچه نمی‌بینید!</title>
                <link>https://virgool.io/@GreatBahram/timing-and-profiling-eibfj1zehr8h</link>
                <description>Timing and Profiling Codeمقدمهسلام به همگی!این هفته می‌خواهیم دو نوع ابزار خیلی خوب واسه اندازه‌گیری سرعت برنامه‌های پایتون معرفی کنیم.فرض کنیم برای انجام یک کار، چند تا راه حل داریم و می‌خواهیم ببینیم کدوم‌اش‌ بهینه‌تر هست. این کار رو چطور انجام بدیم؟ معیارهایی که می خواهیم بررسی کنیم تجربی هستند. یعنی سراغ راه‌حل‌هایی مثلBig Notation و ... نمی‌ریم.به عنوان مثال فرض کنید یه برنامه ساده داریم که دو ماتریس رو توی هم دیگه ضرب می‌کنه و سه تا راه حل این شکلی داریم:حالا می‌خواهیم ببینیم کدوم یکی از این سه راه حل از سرعت بهتری برخوردار هست؟روش اولیک راه حل ساده این هست که ابتدای کار زمان سیستم رو چک کنیم و وقتی هم تست‌هامون به پایان رسید یک بار دیگه زمان رو چک کنیم و ببینم تفاضل این دوتا چقدر بوده، چیزی شبیه پایین:How to time something in Python.اینجا ما با کمک ماژول time این کارو انجام دادیم. این ماژول چندین فانکشن واسه انجام این کار داره، ممکن هست شما قبلا از فانکشن time.time یا time.process_time استفاده کرده باشید. مشکل اولی این هست که روی همه‌ی پلتفرم‌ها از دقت یکسان برخودار نیست و دومی هم زمان sleep داخل برنامه رو حساب نمی‌کنه. بهمین خاطر کلا بهتر هست که از perf_counter استفاده کنید، کار کردن با این فانکشن‌ها خیلی ساده است؛ به تنهایی معنا ندارن و باید دوتا از اونا داشته باشین و تفاضل‌شون میشه زمانی که صرف کار شما شده.اگر از طرفداری Jupyter Notebook هستید اونجا اتفاقا با راحتی بیشتری می‌تونید این کارو انجام بدید:How to time something in the Jupyter Notebookمزیت‌ این روش ساده بود‌ن‌اش هست و اما عیب‌اش چیه؟ عیب این روش اینه که کامپیوترها در هر لحظهِ وضعیت‌های متفاوتی دارن:The downside of simple timing is its variance.به همین خاطر شاید بهتر باشه که حداقل چندبار اجراش کنیم و نهایتاً میانگین خروجی‌ها رو معیار قرار بدیم.اما به جای اینکه این کارو خودمون انجام بدیم، می‌ریم که با کمک روش دوم این مساله رو برطرف کنیم.روش دومیک ماژول دیگه داخل پایتون هست به اسم timeit که رسالت خودش رو اینجوری معرفی می‌کنه:Measure execution time of small code snippetsمی‌بینید دیگه که میگه من ساخته شدم واسه انداز‌ه گیری کدهای کوچیک. این ماژول خیلی باحاله، نه تنها داخل کدمون می‌تونیم ازش استفاده کنیم، بلکه امکان فراخونی داخل کامندلاین رو هم داره. کلا یه ابزار خیلی خیلی کاربردیه واسه اینجور مواقع‌ است.یه مدل از اجرای کامند‌لاینش رو با هم ببینیم:با پارامتر n- مشخص می‌کنیم که قطعه کد داده شده رو چند بار اجرا  کنه و خود کد رو به صورت یک رشته به عنوان آخرین ورودی بهش می‌دیم (این ماژول به کد ما میگه statement). توی حالت اول می‌بینیم که گفته حدودا ۱۰ مایکروثانیه زمان برده و وقتی مجموع ده برابری ‌اش رو حساب کردیم یکم بیشتر از ده برابر شده (این زمان حاصل تقسیم کل زمان اجرا بر تعداد اجرا‌ها هست).حالا فرض کنید کارِ مشابه بالا رو این سری با NumPy انجام بدیم. یه جایی نیاز داریم که NumPy رو import کنیم. میشه داخل کدی که بهش میدیم بذاریم؛ اما نکته‌اش اینه که اونجا باید چیزهایی رو بذاریم که میخواید n بار تکرار بشه. چیزهایی که ثابت هستند و یکبار اجراشون برای n بار کفایت می‌کنه به عنوان setup بهش پاس می‌دیم:The point is not how much the NumPy is faster than standard library or vice versa, is to learn using setup.همه کارهای بالا داخل مفسر پایتون هم شدنی هست:زمانی که اینجا به ما برمیگردونه مجموع زمانی هست که برای اجرای کد بالا صرف شده. در حالی که توی نسخه command-line میانگین زمان رو به ما نشون می‌داد.ولی کلا به نظر میرسه کار کردن باهاش یکم سخت هست چون اینجوری هر سری باید قطعه کد مورد نظرمون رو بیاریم تبدیل به یک رشته کنیم بعد بدیم به تایم‌ایت! به عبارت دیگه مشکل اینه که اقای تایم‌ایت به متغییرها و فانکشن‌های داخل مفسر دسترسی نداره.Poor timeit module is blind just like love.اما این مساله به راحتی قابل برطرف شدن هست، کافیه namespace (or better to say symbol table) خودمون رو باهاش به اشتراک بذاریم اینجوری همه چیزهایی که ما داخل مفسر تعریف کردیم میبینه:Let&#039;s cure the timeit&#039;s blindness.خیلی خب حالا که حسابی تبرمون رو تیز کردیم بریم یه مقایسه بین سه فانکشنی که نوشتیم داشته باشیم:Comparison is the thief of joy.همون‌طور که انتظار داشتیم نامپای خیلی سریع‌تر از دو حالت بالاست. مشابه روش اول این کار رو میشه داخل Jupyter Notebook هم با راحتی بیشتری انجام داد ( یه نگاهی هم به timeit%% بندازید):Using timeit module inside the Jupyter Notebookاین ابزار جدید، timeit،‌ خیلی از جاها به کمک‌تون میاد و اگر دقت کنید معمولاً ادم‌ها توی Stackoverflow از اون برای این استفاده می‌کنند که مقایسه‌ای بین چند راه‌حل داشته باشن. مثلا اینجا پرسیده شده که چرا تاپل‌ها توی پایتون سریع‌تر از لیست‌ها هستند؟ یا اینجا می‌تونیم تفاوت list-comprehension در مقابل for-loop ببینیم.موضوع دوم پروفایلینگابزارهای بالا توی رده بنچمارکینگ می‌گنجند یعنی ما فقط یک دید کلی داریم که چقدر زمان برده تا کار مورد نظر ما انجام بشه. اما یه دسته دیگه از ابزارهای مفید، پروفایلر‌ها هستند. پروفایلر‌ها به ما کمک می‌کنند که کندترین بخش برنامه‌مون (bottleneck) رو پیدا کنیم و اگر راهی هست بریم اون رو برطرف کنیم.پروفایلرهارو دو دسته کلی دارند:اولی Determinticها: این دسته از پروفایلر‌ها در کل زمان اجرا برنامه‌ی شما رو رصد می‌کنند یعنی هر فانکشنی هر عملی که انجام بشه رو زیر نظر دارن و به همین دلیل overhead زیادی به برنامه تحمیل می‌کنند. خیلی خودمونی بگیم نسبت به حالت عادی برنامه کندتر اجرا میشه و معمولاً توی محیط تست و توسعه استفاده میشن. پروفایلی که خود پایتون به صورت پیش‌فرض داره، cProfile، جز این دسته است.دومی Sampling/Statistical:‌ این روش به جای اینکه از ابتدا تا انتهای برنامه رفتار برنامه رو رصد کنه،‌ توی بازه‌های مشخصی نمونه گیری میکنه خب اینجوری سربار خیلی خیلی کمتر میشه اما دقت هم از اون طرف کمتر کاهش پیدا می‌کنه. داخل این دسته هم باز یه تنوع‌هایی داریم مثلا یکی حتما باید روی سیستم‌تون نصب بشه و کد رو باهاش اجرا کنید،  Pyinstrument. یکی دیگه میگه external هست یعنی نیازی نیست که برنامه‌تون رو تغییر بدید فقط‌ بهش یک PID میدید و این شروع به جمع‌اوری اطلاعات می‌کنه،‌ مثل py-spy، این باعث میشه که py-spy یه گزینه‌ی خیلی خوبی برای محیط‌های پروداکشن باشه.توی مثال پایین ما یک برنامه خیلی ساده داریم که ادای یک کار مثلا وقت گیر رو در میاره:Our pretty simple exampleبعدش برای پروفایل کردنش به صورت پایین عمل کردیم. آپشن o- مشخص می‌کنه که خروجی پروفایلر کجا ذخیره بشه:How to use python built-in profiler?خروجی cProfile یک فایل باینری هست که با ابزارهای مختلفی میشه پارسش کرد. یک ابزار، داخل خود پایتون هست به اسم pstats که امکان سورت و چاپ خروجی داده رو میده، چیزی شبیه پایین:Parse the profile output via pstats module.خروجی بالا رو باید اینجوری خوندش:روی هم رفته ۱۲ تا فانکشن توی این برنامه صدا زده شده که حدود ۵ ثانیه زمان اجرای همه اونا بوده. و گفته که براساس cumulative time مرتب شده که جلوتر میگم چی هست.فیلد اول ncalls: تعداد فراخوانی‌ها رو نشون میده. به طور مثال، چون ما دو بار تابع پرینت رو اجرا کردیم میبیند دومی از اخر که فانکشن پرینت هست ncallsاش دو هست.فیلدهای tottime: اینجا کل زمان صرف شده برای اجرای اون فانکشن بجز زمانی که صرف اجرای زیر مجموعه‌هاش شده. فیلد بعدی‌اش percalls میشه تقسیم tottime بر تعداد اجرهایی که داشته.فیلد cumtime: مدت زمان اجرای فانکشن بعلاوه زیرمجموعه‌هاش رو نشون میده که مشابه قبلی اینجا هم percalls تقسیم اون زمان بر تعداد اجرای اون فانکشن رو به ما میگه.در نهایت اسم فانکشن‌ای که اجرا شده و به همراه شماره خط اون رو می‌بینیم.یک ابزار خوب دیگه هم که میشه با اون خروجی پروفایلر رو به صورت گرافیکی دید snakeviz هست.برای مثال ما خروجی‌اش اینجوری میشه:Or you could the famous Snakeviz module.بعضی‌ها به پروفایلر پایتون ایراد می‌گیرند که وقتی کد خودم رو پروفایل می‌کنم دنبال اشکال داخل کد خودم می‌گردم چرا باید فراخوانی‌های داخلی پایتون رو هم توی خروجی ببینم؟ برخلاف cProfile دو ابزار Pyinstrument و scalene اینجوری کار نمی‌کنن و فقط خطوط برنامه‌ی خودتون رو نشون میدن. ابزار Scalene یه حسنی هم داره که درصد استفاده از CPU و Memory رو هم جداگانه نشون میده، اما توی cProfile ما فقط با wall-clock سروکار داریم.داخل Jupyter notebook هم باز میشه تقریبا اکثر این کارها رو انجام و اینجا می‌تونید چند مثال از این حالت ببینید.جمع بندیقبل از اینکه این مطلب رو تموم کنم، دوست دارم به این نکته اشاره کنم که در حین توسعه دیوانه‌وار دنبال  بهینه سازی نباشید. یه جمله‌ای هست که میگه:Make it work, make it right, [and then] make it fast.من خودم تمام تلاشم رو می‌کنم که تا جای ممکن از پیش بهینه‌سازی جلوگیری کنم. امیدوارم که از این مطلب چیزی یاد گرفته باشید و اگر هم دوست داشتید این مطلب رو با دوستاتون به اشتراک بذارید.از اینجا کجا بریم؟Python Timer FunctionsPython standard libraries: time, timeit, profileIntroduction to cProfile and Snakeviz [Youtube]Beyond cProfile [Youtube]</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Sat, 23 Jan 2021 10:42:25 +0330</pubDate>
            </item>
                    <item>
                <title>یکبار برای همیشه - Dataclasses</title>
                <link>https://virgool.io/@GreatBahram/once-for-ever-dataclasses-dyvq6gzedbjj</link>
                <description>Dataclass is awesome!یکی از ویژگی‌های که توی پایتون ۳.۷ معرفی شد، ماژول dataclasses هست. دیتاکلاس‌ها به وجود اومدن تا جلوی تکرار کد‌های یکسان (boilerplate) رو بگیرن. دیتا‌کلاس جز یک مفهوم‌ بزرگتری به اسمCode Generator هست، که هدف از ساخت Code Generator اینه که یک سری کارهای تکراری و بدون پیچیدگی رو به خود کامپایلر/مفسر واگذار کنیم و وقت‌مون رو بیشتر روی بخش‌های مهم برنامه بذاریم.پس مزایای Code Generator اینه که:یک کار ساده و تکراری رو برای ما انجام میده. دوم اینکه، برنامه‌ی ما رو ساده می‌کنه (از لحاظ خونایی و تعداد خط کد) و در عین حال باعث افزایش کیفیت برنامه هم میشه.خوب هست که قبل معرفی خود دیتاکلاس یه سری به تلاش‌های قبلی بزنیم که توی پایتون انجام شده.History helps us develop a better understanding of our world (I mean the Python world!)احتمالا خواننده‌های این مطلب می‌دونن که collections.namedtuple که توی پایتون 2 هم وجود داشته؛ در حقیقت میشه گفت نسل اول code generator در پایتون همین namedtuple بوده. Namedtuple معمولاً اینجوری معرفی میشه که ‌tuple‌ها امکان دسترسی به داده رو فقط از طریق indexing میده (بهمین خاطر بهش می‌گیم Sequence)، اینجوری:how to use a tupleو این خوانایی کد رو پایین میاره؛ در حالی که با کمک namedtuple ما می‌تونیم از طریق اسم attribute به اون دسترسی داشته باشیم (به عبارت درست‌تر می‌تونیم از dot notation لذت ببریم):namedtuple is coolاین tupleها و namedtupleها یک سری محدودیت و امکانات دارند، که در پایین راجعبه اونا صحبت می‌کنیم:این tupleها immutable هستند، یعنی شما نمی‌تونید بعد از تعریف‌شون برید مقدار داده‌هاشون رو تغییر بدید. این حرف برای namedtuple هم صدق می‌کنه.با توجه به مثال بالا، namedtuple خوانایی کد ما رو بالا برده و علاوه بر اون یک سری امکانات دیگه هم به ما داده که شاید در نگاه اولیه دیده نشن.خیلی از مواقع وقتی قصد مقایسه بین آبجکت‌ها رو داریم، tuple comparison واقعاً گزینه خوبیه چون به صورت پیش‌فرض اینا این ویژگی رو پشتیبانی می‌کنند و کار ما رو راحت می‌کنند.مثلاً فرض کنید، می‌خواهیم زبان‌های برنامه نویسی رو بر اساس اسم‌شون مرتب کنیم:What does tuple comparison mean?همون‌طور که می‌بینید آبجکت‌های ما قابلیت مقایسه با هم دیگه رو دارن. دو تا متدی که قابلیت orderability و Equality رو به ما میدن اینا‌ هستن:__lt__, __gt__, __ge__, __le__ # Order-ability methods__eq__ # Equality or Comparison methodیکی دیگه از ویژگی‌های خوبی دیگه‌ای که tuple‌ها دارند، unpacking هست. مثلا:Aha! This is unpacking!این ویژگی این امکان رو میده که خیلی راحت‌ به attribute‌ها یا داده‌های هر آبجکت بدون نیاز indexing دسترسی داشته باشیم (این رفتار توسط متد __iter__ پیاده‌سازی میشه).و نهایتاً این که namedtuple برای ما یک string representation عالی هم فراهم می‌کنه:String representationپس می‌بینید که namedtuple علی‌رغم تعریف یک خطی‌اش، متد‌های متفاوتی رو برای ما پیاده‌سازی کرده، تا کار رو مارو بسیار راحت کنه. ولی دو تا ایراد اصلی هم این namedtuple داره:اولاً، راه‌ حل آدمیزادی واسه تعیین مقدار اولیه هر attribute وجود نداشت.دوم، اینکه نوع متغیر رو به سختی می‌شد با ایده جدید Type Hints مشخص کرد.این مشکلات باعث شد که یک namedtuple جدید typing.NamedTuple ساخته بشه. مثال قبلی با سیستم جدید:Using typing.NamedTuple is not that much bad!خب، همون‌طور که می‌بینید استفاده از این آبجکت جدید، نیازمند subclass کردن اون هست و اینکه کنار هر فیلد، نوع اون رو به صورت اختیاری می‌تونیم مشخص کنیم. با کمک typing.NamedTuple دو مشکل اساسی collections.namedtuple تا الان حل شدند، یعنی هم می‌تونیم مقدار پیش‌فرض برای بعضی attribute‌ها مشخص کنیم و هم‌ اینکه از type hints ها لذت ببریم.یادمون باشه namedtupleها واقعا توی لایه‌های پایینی tuple هستند و بعضاً tuple رفتاری داره که ما دوست نداریم آبجکت ما داشته باشه. به طور مثال، ممکنه مقایسه دو نمونه از کلاس Car معنایی نداشته باشه؟ یا از اون بدتر add operator بین دو نمونه از namedtuple به یک چیزی میرسه که ما نمی‌خواهیم کاربر با آبجکت‌ های ما همچین رفتارهایی بکنه:Things that you should be cautious about itبنظر می‌رسه ما هنوزم با اون چیزی که می‌خواهیم خیلی فاصله داریم. چی‌ میشه اگر ما بخواهیم یک آبجکت با کمک اینا بسازیم اما immutable نباشه، اتفاقاً می‌خواهیم تغییرش هم بتونیم بدیم. یا بعضی فیلد‌ها توی مقایسه استفاده بشن، بعضی‌های دیگه استفاده نشن.معرفی dataclassدیتا کلاس یه class builder هست که اومده تا چالش‌هایی که اینجا راجعبه‌شون صحبت کردیم رو برای ما حل کنه. به طور کلی میشه گفت که dataclass برای نگهداری داده‌ یا attribute ساخته شده، اما واقعاً هیچ محدودیت فنی برای اضافه کردن method به اون کلاس وجود نداره.ماژول dataclasses دو تا api اصلی داره:اولی یک دکوریتور هست که اسم‌اش dataclass هست.دومی یک متدِ به اسم field هست برای سفارشی‌سازی attributeهای کلاس تعریف شده.اول از همه بریم ببینیم کار با این دوست‌ جدیدمون چطوری هست:This is what I wanted from the beginning!پس برای پیاده‌سازی نیازی به subclass کردن چیزی ندارم و خیلی راحت به صورت decorator ازش استفاده می‌کنیم و پایین‌اش علاوه بر اسم attribute‌ها و کنار اون باید نوع attributeها رو مشخص کنم.به صورت پیش‌فرض هر کلاسی که ساخته میشه، یک string representation و مقایسه (Equality not order!) رو با خودشون برای ما میارن، اینارو با هم ببنیم:You get what you said!به صورت پیش‌فرض کلاس‌هایی که با dataclass ساخته می‌شن mutable هستند (قابل تغییر هستند):فرق dataclass با خونواده namedtuple این هست که اینجا شما چندین keyword-argument دارید که با کمک اونا می‌تونید کلاس ساخته شده رو تا حد زیادی تغییر بدید. مثلاً اینجوری می‌تونیم بگیم که کلاس ما immutable باشه:یا می‌تونیم برای هر فیلدی که خواستیم مقدار اولیه مشخص کنیم:برای لیست کامل این keyword-argumentها خود مستندات‌اش رو بخونید. همون‌طور که گفتیم ماژول dataclasses یک آبجکت دیگه به اسم field داره، که با کمک اون به صورت خیلی عمیق‌تری می‌تونیم کلاس ساخته شده رو customize کنیم. مثلا ممکن هست بخواهیم یک فیلد توی __repr__ ما نشون داده نشه. یا فلان فیلد خاص توی مقایسه هیچ نقشی نداشته باشه.به طور کلی میشه این ماژول dataclasses داره متدهایی جادویی رو برای ما تعریف می‌کنه (Magic methods).و این پتانسیل رو داره که باعث افزایش کیفیت کد ما هم بشه.جمع‌بندیوقتی با پایتون کار می‌کنیم با کلی آبجکت سروکار داریم که از نظر کیفیت کد در سطح بالایی قرار دارند. هدف ما هم باید این باشه که تا حد زیادی خودمون رو به اون سطح نزدیک کنیم. یکی از ابزارهایی که به ما در رسیدن به این هدف کمک می‌کنه dataclass هست.دیتاکلس‌ها برای کلاس‌های ساده‌ای که تعریف می‌کنیم و پیچیدگی زیادی نداره، خیلی گزینه خوبی هست. اما من خودم وقتی برای کارهای پیچیده‌ ازش استفاده کردم، دیدم بهترین گزینه نبوده.از اینجا کجا بریم؟ویدیودو تا از ویدیوهای خوبی که من دیدم رو پایین اوردم، یکی‌شون راجعبه تاریخچه و نحوه ساخت و کار کردن dataclass هست؛ ارائه دوم با ایده‌ی اینکه dataclass می‌تونه کد ما رو ساده و تمیزتر کنه ساخته شده.صحبت‌های ریمند هتینجر راجعبه Dataclassesویدیوی دوم ارائه تری هانر با عنوان Easier Classesاینجا مقایسه کلی بین سه ماژول attrs، dataclasses و pydantic صورت گرفته و توضیح میده که هر کدوم چه ایرادتی دارند.اینجا هم خیلی عمیق‌تر راجعبه dataclasses صحبت شدهیکی از مشکلاتی که همون ابتدای کار با دیتاکلس‌ها باهاش روبرو می‌شید ارتباط property و دیتاکلس هست، توی لینک بالا راجعبه این موضوع صحبت شده. یکی دیگه از چالش‌ها ارث‌بری توی دیتاکلس هست.</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Tue, 16 Jun 2020 15:16:21 +0430</pubDate>
            </item>
                    <item>
                <title>خلاصه کتاب - Atomic Habits</title>
                <link>https://virgool.io/@GreatBahram/book-summary-atomic-habits-kn3k91ra9pzc</link>
                <description>Book-Summary-Atomic-Habitsمقدمهسلام، هدف من از نوشتن این دسته از مطالب اشتراک مطالب مهم از کتابی هست که خوندم و نظر کلی خودم راجعبه کتاب می‌گم. اگر قصد خوندن کتاب رو دارید شاید این مطلب مناسب شما نباشه چون هدف من نوشتن خلاصه‌ ای از کتاب هست (i.e spoiler alert).کتاب Atomic Habits توسط جیمز کلیر نوشته شده و یکی از کتاب‌های پرفروش هم بوده. از حیث دسته‌بندی جز دسته توسعه فردی قرار می‌گیره و در کل نویسنده هدف‌اش ارائه یک چارچوب برای ایجاد عادت‌های خوب و همین طور خلاص شدن از عادت‌های بد هست.ترجمه کتاب: من نسخه انگلیسی این کتاب رو خوندم؛ ولی نشر نوین هم مثل اینکه این کتاب رو ترجمه کرده و از طریق ایبوک‌های ایرانی هم قابل تهیه هست.ایده‌ی اصلی: معرفی یک چارچوب برای ساخت عادت‌های مفید و همین‌طور یک بخش کوچیکی رو هم به راجعبه ترک عادت‌های بد اختصاص داده. ساختار کتاب تقریبا با ایده نویسنده سازگار هست و فصل‌های کتاب خیلی کم حجم نوشته شده تا کسایی که کتاب خوندن عادت همیشگی‌شون نیست هم بتونن کوچولو کوچولو کتاب رو تموم کنن.خلاصه کتابکتاب با بخشی از زندگی نویسنده شروع میشه که در حین بازی چوب بیسبال به صورت‌اش برخورد می‌کنه، به دلیل آسیب‌هایی که می‌بینه از فرصت‌های ورزشی مد نظرش یه جورایی عقب می‌افته. اما با ورودش به دانشگاه با شروع انجام کارهای کوچیک در بازه طولانی دستاورد‌های بزرگی نصیب‌اش شده، کم کم جذب کلاً فرایند نحوه ساخت عادت‌ها میشه.نویسنده در بخش اول عناصر اصلی عادت رو بررسی می‌کنه، که: سرنخ، اشتیاق، پاسخ، و پاداش هستند. و بعد از اون یک چارچوب برای ساخت عادت جدید و ترک عادت های بد معرفی می‌کنه.چارچوبی که نویسنده پیشنهاد میده چهار رکن اصلی داره:واضح بودن: این متناظر با عنصر اول عادت، سرنخ هست. نویسنده اینجا توضیح میده که چطور رفتارهای ما با سرنخ‌ها گره خورده. برای افزایش موفقیت عادت جدید، سرنخ‌هاش باید دم‌دست باشه؛ برای ترک عادتی که دوست نداریم کافیه که سرنخ‌هاشو از خودمون دور کنیم و فرصت زنده‌ شدن اون رفتار رو ازش بگیریم.جذابیت عادت: جذابیت چیزی هست که باعث ایجاد اشتیاق برای انجام اون کار میشه. برای اینکه یه کار رو انجام بدیم باید یه جوری برای خودمون جذاب‌اش کنیم و برعکس کاری رو که نمی‌خواهیم انجام بدیم با نشون دادن ویژگی‌های بدش، از جذابیت‌اش بکاهیم.انجام‌اش راحت باشه:  آقای کلیر، یک ایده‌ای داره می‌گه اوایل که یک کار رو می‌خواید شروع کنید، سعی کنید فقط دو دقیقه اون کار رو انجام بدید! بحث می‌کنه که حضور (Show-up) شما توی اون عادت به مراتب مهم‌تر از خروجی اون کار هست. چون هدف‌ ساخت یه هویت جدید هست. مثلا، اگر هر روز دو دقیقه مطالعه کنید، شما یک هویت کتاب‌خون برای خودتون ساخته‌اید؛ بعدش می‌شه این رو توسعه‌ داد، بیشتر روش زمان گذاشت. اما از اول نباید توی تله‌ی توسعه افتاد (The best is the enemy of the good). هویت مهم‌تر از نتیجه‌ است.رضایت‌بخش باشه: برای اینکه یه رفتار ادامه پیدا کنه، لازم هست که اون تجربه رضایت بخش باشه. از نظر بیولوژی انسان به پاداش‌های زودهنگام عادت داره، نویسنده میگه سعی کنید، عادت‌/رفتار های جدید رو با پاداش‌های زودهنگام وصل کنید تا مطمئن بشید اونارو در طولانی مدت هم انجام می‌دید. همین که یک تقویم داشته باشید، و روزهایی که اون کارو انجام دادید تیک‌بزنید، می‌تونه رضایت نسبی درونی ایجاد کنه.در هر فصل‌هم کنار معرفی ایده‌ها سعی می‌کنه روش‌ها/ابزارهایی برای عملی کردن اون ایده معرفی کنه. هر فصل از چهار بخش تشکیل شده و بخش آخر معمولا به نحوه کمک کردن از اون رکن چارچوب معرفی شده برای ترک عادت‌های بد هست. خلاصه این ابزارها در قابل یک فایل pdf هم در دسترس هست.متن کتاب خیلی شبیه کتاب های مارتین گلدول هست، از این حیث که شما با علم سروکار ندارید، بلکه ادعای نویسنده این هست که علم (رفرنس‌های داخل کتاب) پشتوانه‌ای برای صحبت‌های من هست.افزونه‌های کتابفرهنگ جدید که بین نویسنده‌ی کتاب‌های پرفروش رایج شده این هست که ارتباط شما و نویسنده بعد از خوندن کتاب قطع نمی‌شه، بلکه شما رو توی جای جای کتاب به سایت یا پادکست‌ خودش سوق میده، جیمز کلیر هم از این قاعده مستثنی نیست.آقای کلیر، یک وب‌سایت داره که در انتهای کتاب هم راجعبه‌اش صحبت می‌کنه و علاقه‌مند هست که شما رو عضو خبرنامه‌ی خودش کنه، اونجا معمولاً بستری برای انتقال مطالب تکمیلی و چیزهای جدید به خواننده‌هاست.علاوه بر این، یک دفترچه/کتاب داره که برای ثبت عادت‌ها و اندازه‌گیری ممکن هست به شما کمک کنه.در میهن عزیز خودمون هم، پادکست هلی‌تاک راجعبه این کتاب صحبت کرده و همین‌طور یک دفترچه‌ با اسم دفترچه برنامه‌ریزی طراحی کردن، که ایده‌‌شون تقریبا با جیمز کلیر یکی هست.اما اشکال همه اینه که می‌خوان یه چیزی به ما بفروشن، آقای کلیر می‌تونست یه کار مثبت بکنه، یک‌سری فایل اکسل ساده برای اندازه‌گیری یا رصد عادت جدید معرفی می‌کرد. کلاً، توی دنیای مدرن باید حواسمون باشه که توجه‌/زمان خودتون رو به چیزهای بدید که واقعا ارزش دارند.نکته‌های آخراینجا معمولا چیزهایی که توی کتاب به چشم‌ من اومده صحبت می‌کنم.اصطلاح verbal اشاره به هر چیزی داره که به کلمات مرتبط هست، بیشتر اشاره به چیزهای نوشتاری داره ولی شامل چیزهای گفتاری هم هست.توی کتاب Verbal advantage نویسنده یه بحثی رو باز می‌کنه، که توی انگلیسی یه اشتباه مصطلحی شکل گرفته که مردم به جای استفاده از orally از verbally استفاده می‌کنند، در حالی که منظورشون orally یا گفتاری هست، دارن یک چیز بزرگتر رو که بخشی ازش میتونه گفتاری باشه استفاده می‌کنند، مثلا:Ensure all promises made verbally are included, in writing, in the contract.اینجا نویسنده هدف‌اش این بوده که بگه تمام چیزهای صحبت شده توی قرارداد نوشته میشه، اما در حقیقت داره می‌گه تمام چیزهای کتبی و گفتاری در قرارداد قید بشه. شاید بهتر بود اینجوری بگه:Ensure all promises made orally are included in the contract.توی این کتاب‌ هم چندین جا این نکته به چشم میاد:Whenever we are preparing to walk out the door for a trip, she verbally calls out the ... (Page 62)Pointing-and-Calling raises your level of awareness from a non-conscious habit to a more conscious level by verbalizing your actions. (Page 67)اینجا دیگه اشک در چشمان اهل قلم حلقه می‌زنهA habit contract is a verbal or written agreement ... (Page 208)جمع‌بندیدر کل، میشه گفت کتابی خوبی هست، راهکارهای خوبی برای رسیدن به چیزهایی که می‌خواهیم بهشون برسیم بهمون میده. خیلی از جاها نویسنده واقعا تمام تلاش‌اش رو می‌کنه که فقط انگیزه‌ی کاذب ایجاد نکنه و یک سیستم/چارچوب برای رسیدن به چیزهایی که می‌خواهیم به ما معرفی کنه.هدف‌ من از نوشتن این خلاصه‌، اشتراک چیزی هست که خوندم. اینجوری هم ممکن هست کسی از این‌ کتاب‌های معرفی شده خوشش بیاد و هم اینکه من فرصتی پیدا می‌کنم بیشتر راجعبه محتوای کتاب فکر کنم.</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Tue, 19 May 2020 11:45:16 +0430</pubDate>
            </item>
                    <item>
                <title>یک‌بار برای همیشه - Descriptor</title>
                <link>https://virgool.io/@GreatBahram/once-for-ever-descriptor-hgdwzld1qler</link>
                <description>Oh! Descriptors, after all!سلام!توی این قسمت از یکبار برای همیشه هدف‌مون معرفی Descriptor هست. در یک‌بار برای همیشه بحثی رو مطرح می‌کنیم که خیلی در نگاه اول شاید راحت بنظر نرسه، و سعی می‌کنیم با بیان ساده‌تر و مثال‌های خیلی خیلی ابتدایی اون مطلب رو به راحتی به مخاطب انتقال بدیم.از اون‌جایی که Descriptor جز مفاهیمی هست که شاید توسعه‌دهنده‌های پایتون، به صورت خود‌جوش به سمتش نرن و همچنین عدم وجود مطلب در این زمینه از جمله دلایلی باشه که این مفهوم سخت بنظر برسه، تصمیم گرفتم که این مطلب رو بنویسم.علاوه بر این، descriptorها چون در موارد خاصی به کار گرفته می‌شوند، طبیعی هست که بعد از یک مدت دانش ما در این رابطه کم‌رنگ‌تر بشه.تمام‌ کدهایی استفاده شده، اینجا قابل دسترس هستند.مقدمهدر قسمت قبل راجبعه property صحبت کردیم (اگر این قسمت رو نخوندید حتما پیشنهاد میشه قبل از خوندن این مطلب، بخش قبلی رو بخونید) و گفتیم معادل Setter/Getter در پایتون هست و هم باعث خوانایی کدمون میشد و می‌تونستیم از lazy loadingاش بهره ببریم.به این نتیجه هم رسیدیم که property ها جزئی از یک مفهوم بزرگتری به نام descriptor هستند، که بستری رو برای  مدیریت دسترسی به attributeهای یک آبجکت رو فراهم می‌کنند. و همچنین گفته شد که اساساً attributeها سه عمل رو پشتیبانی می‌کنند:دسترسی به مقدار attributeaccess to an object&#039;s attributeتغییر مقدار attributemodify an object&#039;s attributeحذف مقدار attributedelete an object&#039;s attributeتوی مثال قسمت قبل، که هدفمون مدیریت مقادیر منفی بود، با کمک property این عمل‌ رو مدیریت کردیم. اما چون تعدادشون زیاد بود، به این فکر افتادیم که شاید property بهترین راه‌حل نباشه و راجعبه یک راه‌حل بهتر هم یکم صحبت کردیم: Descrtiptor.فرض کردیم اگر یه descriptor به NonNegative داشتیم چقدر کارمون راحت‌تر می‌شد. توی قطعه کد پایین ما یکبار یک Descriptor تعریف کردیم که به محض دریافت ورودی چک می‌کنه اگر مقدار ورودی منفی باشه خطا میده؛ اگر نه ورودی رو توی آبجکت ما ذخیره می‌کنه. این کد با اون روش که یک منطق رو هی تکرار می‌کردیم واقعا قابل مقایسه نیست.Movie objectحالا توی این قسمت، اول از همه خود Descriptor رو تعریف می‌کنیم بعدش قدم به قدم، متد‌های لازم رو پیاده‌سازی می‌کنیم و نهایتا دو مثال پیاده‌سازی شده از descriptor با هم می‌بینیم.به چه چیزی descriptor گفته میشه؟احتمالاً شما خیلی از جاها Descriptorها رو دیدید، اما شاید در اون برهه از زمان، خودِ descriptor برای شما اهمیت نداشته. مثلاً توی اکثر فریم‌ورک‌های وب از descriptor برای ساخت مدل در دیتابیس به صورت زیر استفاده میشه:Flask-SQLAlchmey یک نکته‌ای که خوب هست بهش توجه بشه این هست که تمام این متغییرها بیرون از متدِ __init__ نوشته شدند و در نتیجه همه‌ی اونا Class variable محسوب می‌شن.اما بریم ببینیم descriptor چی هست؟به زبون خیلی ساده descriptor آبجکتی هست که یک سری رفتار رو به attribute های مورد نظر bind  (وصل) می‌کنه.از نظر فنی، هر کلاسی که یکی از متدهایی زیر رو داشته باشه بهش descriptor می‌گیم:متد __get__، که وقتی قرار هست به مقدار attribute دسترسی داشته باشیم اجرا میشه.متد __set__، که هنگام set کردن مقدار به attribute اجرا میشه.و نهایتا __delete__، که هر موقع قصد حذف یک attribute رو داریم اجرا میشه.هر کدوم از این متد‌ها یه ورودی‌های ثابتی می‌گیرن که چون اساسا descriptor یک پروتکل هست و  خود پایتون معمولا با این متد‌ها تعامل داره، نه کاربر!یادآوریبرای اینکه ببینیم هر آبجکت توی پایتون چه attribute داره از متد ‍&#x60;__dict__&#x60; کمک می‌گیریم. یه راه دیگه هم که خوناتر هست اینه که از تابع vars استفاده کنیم.Get a list of an object or class attributesهمین تابع رو روی خود کلاس اگر صدا بزنیم، خروجی‌اش این میشه:اولین متد، متد getهمون‌طور که گفتیم متد __get__ برای دسترسی به مقدار یک attribute اجرا میشه. این متد علاوه بر خود آبجکت (self) دو تا ورودی دیگه هم داره.Descriptor get methodتوی مثال بالا، ما متد __get__ رو تعریف کردیم، متد get دو تا ورودی داره: instance و obj_type.توی مثال بالا m یک instance از کلاس Movie هست و خود کلاس Movie نقش obj_type رو داره. ورودی obj_type معمولا خالی هست، مگر موقعی که attribute از طریق کلاس صدا زده بشه مثل پایین (دقت کنید از Movie هیچ instance ای ساخته نشده):توی این حالت، instance مقدار None رو داره. چون دیگه با سروکار ما با instance نیست. ما در حقیقت از خود کلاس آگاه هستیم تا بتونیم کاری کنیم که descriptor ما صدا زدن از طریق class - بدون ساختن instance  - رو داشته باشه. عملا، کاری که پایتون تو لایه‌های زیرین داره انجام میده این جوری هست: حالت دوم، وقتی هم هست که از طریق یکی از instanceهای Movie به price می‌خواهیم دسترسی داشته باشیم. مثل:که پایتون این‌جوری در حقیقت داره descriptor ما رو فراخوانی می‌کنه:پس توی این حالت ما هم به instance و هم به type آبجکت دسترسی داریم. اگر توضیحات یکم گیج‌تون کرده ادامه بدید جلوتر شفاف تر میشه.متد set و deleteاین متد (__set__) همون‌طور که پیداست برای ذخیره/ویرایش attribute هست.Descriptor set and delete methodsهمون‌طور که می‌بینید دیگه توی این دو متد خبری از obj_type نیست و تمام کار ما با instance انجام میشه. اگر هم کنجکاوید که پایتون چجوری داره یک لایه پایین این کار رو انجام میده، مشابه پایین رو انجام میده:و نهایتاً با del کردن یک attribute هم، کارهای زیر انجام میشه:می‌سازمت Descriptorحالا که یکم با خود مفهومش آشنا شدیم بریم سراغ پیاد‌‌ه‌سازی تا به درک خوبی برسیم.مثال اولبریم مشکلی که با property حل نشد رو با descriptor حل کنیم. می‌خواهیم یک descriptor بسازیم به اسم NonNegative که هم بشه ازش داده رو گرفت و هم ذخیره کرد. خب ببینیم توی کد بالا ما چه کارهایی کردیم:بازم تاکید می‌کنم این Descriptor وقتی به صورت class variable استفاده می‌شه، درست عمل می‌کنه. چون پایتون می‌دونه باید بره سراغ متد های مخصوص Descriptor.دومین نکته، اینه که ما داریم تمام مقادیر رو توی instanceهایی از NonNegative ذخیره می‌کنیم (یعنی مقادیر داخل instanceهای Movie نیستن بلکه یه نگاشتی اون وسط اتفاق افتاده). راجعبه این کار حرف و حدیث‌های زیادی هست. در حقیقت برای ذخیره سازی‌ مقادیر دو راه اصلی وجود داره: اول اینکه مقادیر رو توی خود Descriptor ذخیره می‌کنید(مثل همین حالت) یا داخل instanceهای کلاس مورد نظر (مثلاً Movie) که روش دوم (بنظر) منطقی‌تر میرسه. ولی اگر اینا رو ببریم داخل instance ورودی با چه اسمی اونجا ذخیره‌شون کنیم. می‌خوام بگم ما اینجا به اسم متعییر (توی مثال بالا rating) دسترسی نداریم. یکی ممکن هست بگه که کاری نداره می‌تونیم از کاربر بخواهیم موقع استفاده اسم هر متغییر رو هم مشخص کنه و اون موقع به راحتی می‌تونیم داخل خود instance ها ذخیره‌اش کنیم:Getting names at the initialization timeاشکال این کار مشخص هست دیگه؟ یکم غیر منطقی به نظر می‌رسه. اما چی‌میشد اگر این کارو خود پایتون یه جوری مدیریت‌اش می‌کرد؟ خبر خوب اینه که توی پایتون ۳.۶ یه متد دیگه به پروتکل Descriptorها اضافه شده که این امکان رو برای ما فراهم می‌کنه. نحوه استفاده ازشم به صورت پایین هست:Better way in Python 3.6+همون‌طور که می‌بینیم این متد جدید (__set_name__) کار ما رو خیلی راحت کرد (البته اینم بگم که به این صورت نبوده که هیچ‌راه‌حلی قبلش نباشه، توی نسخه ۳.۶ این‌کار راحت‌تر شده). حالا چون اسم متغییر‌ها رو از ورودی گرفتم،‌می‌تونیم به راحتی مقادیر رو داخل لیست ویژگی‌های instance ورودی ذخیره کنیم. حالا اگر یکبار دیگه به اون مثال دیتابیس نگاه کنید می‌بینید اونجا هم عملا هیچ‌کجا بهش اسم متغییر رو ندادیم(توی روش‌های قدیمی تر با کمک metaclass این کارو انجام می‌دادن).یکم بهترممکن هست شما validator های مختلفی نیاز داشته باشید،‌ می‌تونیم کد بالا رو یکم بهتر‌ش کنیم که بتونیم ازش به راحتی بتونیم descriptor های دیگه بسازیم. اول از همه یک Base Class می‌سازیم:Let&#039;s the fun be gin!و حالا می‌تونیم برای هر کار دیگه از این Base classمون استفاده کنیم:انواع Descriptorیه دسته‌بندی هم وجود داره که میگه اگر یک Descriptor فقط متد get رو تعریف کرده باشه بهش non-data descriptor می‌گیم. مثلا این دو تا دوست خوب‌مون staticmethod و classmethod دوتاشون non-data محسوب می‌شن. از اون طرف به descriptor که متد‌های دیگه رو علاوه بر get داشته باشه data descriptor گفته میشه.اما اینکه چرا اینا رو از هم دیگه متمایز کردن، به خاطر نحوه  attribute lookup کردن داخل پایتون هست.یک متد خاصی هست به اسم getattribute که هر بار با attribute های یک ابجکت کار می‌کنیم، یک روال مشخصی رو طی می‌کنه که بتونه اون خصیصه مورد نظر ما رو پیدا کنه (دسترسی به attribute هم مشخص هست دیگه مثلا اینجوری instance.name). این متد سه گام اساسی داره: اول این مشخص می‌کنه این attribute یک data descriptor هست یا نه.اگر نباشه میره داخل خصیصه‌های خود آبجکت (__dict__) دنبال اون خصیصه می‌گرده.توی مرحله سوم،‌اگر پیداش نکرد بررسی می‌کنه ببینه که یک non-data descriptor هست، اگر آره اون رو اجرا می‌کنه.این به چه معنی هست؟ که چی اینا رو گفتی؟ یعنی اگر ما یک non-data descriptor بسازیم،‌ دفعه اول که اجرا می‌شیم (با این فرض که جوری هم پیاده‌سازی‌اش کرده باشیم که حاصل رو داخل خود instance ورودی ذخیره کنیم). سری بعدی که کاربر می‌خواد مقدار attribute رو بگیره. دیگه descriptor ما اجرا نمیشه بلکه توی مرحله دوم بالا می‌مونه، در حالی که اگر data descriptor باشه حتی اگر داخل instance هم مقدار رو ذخیره کنیم هر بار متد get اجرا میشه (توضیح بیشتر این مطلب).مثال دوممی‌خواهیم یک descriptor بسازیم که مشابه property باشه با این تفاوت که مقدار محاسبه شده رو هم کش کنه،‌ اسم‌اش رو هم می‌سازیم cached_property (مشابه این ایده هم تقریبا توی خیلی از پروژه‌ها از جنگو تا خود pip وجود داره).با دانشی که الان داریم می‌دونیم که:با کمک set_name به راحتی می‌تونیم اسم متغییر رو بدست بیاریم.به راحتی می‌تونیم مقدار مورد نظرمون رو داخل instance ورودی ذخیره کنیم.برای اینکه کار هم سخت نشه به صورت non-data پیاده‌سازی‌اش می‌کنیم.Simplified version of cached_propertyاستفاده از اون، این اینجوری میشه (دقت کنید که چون non-data descriptor هست، عبارت computing فقط یکبار چاپ شده)Use descriptors as decoratorیکی ممکن هست بپرسه چرا ما تونستیم به صورت decorator ازش استفاده کنیم؟ چون تمام Descriptorها به صورت پیش‌فرض امکان استفاده به صورت Decorator رو هم دارند، این چیزی هست که به خودی خود وجود داره و نیازی به کاری از سمت شما نداره. بهمین خاطر هست که ما property، classmethod و staticmethod رو به صورت decorator استفاده می‌کنیم.حالا میشه به عنوان تمرین این رو تبدیل به data descriptor کرد و با هم مقایسه‌شون کرد (اون قضیه attribute lookup رو هم بررسی کنید) و حالا که تبدیل به data descriptorش کردید، کاری کنید که بشه مقدار جدید هم بهش داد.البته این رو هم بگم descriptor بالا به صورت non-data داخل کتابخانه‌های پایتون هم وجود داره.جمع‌بندیهمون‌طور که گفتیم property خیلی چیز باحالیه و خیلی از جاها کار ما رو راه می‌اندازه. اما اگر جایی دیدیم که داریم خودمون رو هی تکرار می‌کنیم؛ نشون از وجود راه‌ بهتری هست. و یکی از را‌ه‌ها کمک گرفتن از descriptor هست. حتی اگر از این مفهوم استفاده نکنید؛ امیدوارم که درک‌تون از رفتار آبجکت‌های داخلی پایتون بالاتر رفته باشه.امید‌وارم که از این مطلب چیزی یاد گرفته باشید.از اینجا کجا بریمتمام‌ کدهایی که استفاده شده، اینجا قابل دسترس هستند.اگر علاقمند هستید که بیشتر بدونید، کد‌ پیاده‌سازی property نقطه شروع خیلی خوبی می‌تونه باشه. اگر می‌تونید قبل از خوندن کد، سعی کنید خودتون property رو بسازید.اینجا هم یکی از مراجع اصلی هست که من هم ازش یاد گرفتم و از اطلاعات‌اش اینجا استفاده کردیم.https://nbviewer.jupyter.org/urls/gist.github.com/ChrisBeaumont/5758381/raw/descriptor_writeup.ipynbمعرفی جامع‌تر این موضوع از RealPythonhttps://realpython.com/python-descriptors/</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Tue, 07 Apr 2020 09:31:29 +0430</pubDate>
            </item>
                    <item>
                <title>قانون طلایی گیت ری‌بیس</title>
                <link>https://virgool.io/@GreatBahram/once-for-all-git-2-mvaw1r1tqnp2</link>
                <description>سلام!توی قسمت قبلی، سعی کردیم یه دید کلی نسبت به کارهای که گیت انجام میده بدست بیاریم. راجعبه آبجکت‌های اصلی گیت صحبت کردیم. اما در این قسمت‌ می‌خواهیم که یکم راجعبه مباحث نسبتاً پیچیده گیت صحبت کنیم.مقدمهیکی از مهم‌ترین چالش‌ها در گیت، مرج کردن برنچ‌های مختلف هست که دو مدل اصلی هم داره. و یک سری مفاهیم هم شاید بهش‌ توجه نشده باشه مثل git-revert که توی موقعیت خودش می‌تونه خیلی کمک‌کننده باشه. و در نهایت سعی کردیم یه سری به git-rebase بزنیم هر چند یکم به صورت متنی راجعبه‌اش توضیح دادن سخت هست.در اعماق git-mergeیکی از ویژگی‌های خیلی خوب گیت، نحوه ساخت و مدیریت برنچ‌ها در اون هست. برنچ‌ها رو توی ورژن کنترلر می‌سازیم تا از  آسیب به بخش‌های دیگه جلوگیری کنیم.به طور مثال، وقتی داریم یک ویژگی جدید به سیستم اضافه می‌کنیم آسیبی به کدی که داره درست کار می‌کنه نزنیم. و وقتی هم کارمون به نتیجه رسید می‌تونیم برنچ جدید با برنچ مد نظر به اصطلاح «ادغام» یا مرج کنیم،‌ این کار هم با کمک دستور git-merge انجام میشه.میشه گفت ما دو روش مرج توی گیت داریم:Fast-forwardThree way (No-Fast-forward)قدم اول توی هر دو روش این هست که دستور git-merge دنبال یک گره/جد مشترک (common ancestor) بین این دو برنچ می‌گرده. این جد مشترک هست که مشخص می‌کنه که آیا مرج ما از نوع Fast-forward قابل انجام هست یا روش دوم.Image from https://www.atlassian.comمرج از نوع Fast-Forwardاین مدل فقط در حالتی توسط گیت قابل اجرا هست که ما یک مسیر خطی از نقطه مشترک رفته باشیم: یعنی مثل پایین درحالی که برنچِ Some Feature از Master گرفته شده و تغییراتی هم به اون اضافه شده، گره مشترک (برنچ Master) نسبت به زمانی که ما ازش منشعب شدیم تغییری نکرده (کامیتی بهش اضافه نشده). گیت این مرج‌ها رو خیلی دوست داره و نیازی به تعامل با هم نداره. توی این روش کاری که گیت می‌کنه این هست، که اشاره‌گر برنچ Master رو به نوک برنچ Some feature میزنه؛ به طوری که انگار همه‌ی این تغییرات واقعاً توی همین برنچ ما صورت گرفته.Image from https://www.atlassian.com - git merge fast-forwardاما چی‌میشد اگر علاوه بر برنچ Some Feature، برنچ Master هم تغییر کرده بود؟!توی شکل پایین، برنچِ Some Feature از Master گرفته شده و دو تا کامیت‌ هم داشته، در حالی که خود master هم نسبت به زمانی که ما ازش منشعب شدیم تغییر کرده. توی این حالت دیگر Fast-forward دوای درد ما نمی‌تونه باشه.گیت در اینجور مواقع از روش دوم استفاده می‌کنه، که بهش three-way merge گفته میشه. اسمش‌ از اینجا میاد که گیت باید سه تا اشاره‌گرِ رو بروزرسانی کنه.Image from https://www.atlassian.comخروجی کار به صورت بصری این‌طوری میشه:Image from https://www.atlassian.com - git-merge three-way mergeدر این حالت ما همیشه یک کامیت آبجکت جدید خواهیم داشت و تغییرات رو دیگه توی Master به طور مستقیم وارد نکردیم. بلکه یک اشاره‌گر به تغییرات صورت گرفته زدیم.توی بعضی پروژه‌ها ممکن هست ببینید که سیاست مرج‌، به صورت پیش فرض، مدل بالا بشه. دلایل‌ این کار هم معمولاً:برای برنچ‌هایی که اونجا تغییرات زیادی بوده،‌ maintainer نظرش این هست که تاریخچه به صورت مجزا حفظ بشه و به همین برنچ منتقل نشه.این کار می‌تونه باعث سهولت هم بشه، چطور؟ مثلا اگر بخوایم برگردیم عقب به راحتی برگردیم میتونیم فقط از روی کامیت آبجکت جدید برگشت داشته باشیم، نه کل تغییرات و کامیت‌ها.توصیه به جوانان: میشه یه قاعده سرانگشتی هم داشته باشیم برای خودمون که اگر تغییرات خیلی ساده‌اس همون fast-forward گزینه‌ای خوبی هست ولی اگر تغییرات زیادی صورت گرفته و خود کامیت‌ها و تاریخچه برای ما مهم‌ هست از مدل no-fast-forward بریم بهتر هست.کامند‌لاینبه صورت پیش‌فرض خود گیت سعی در مرج با fast-forward داره و نیاز نیست آپشن‌ خاصی بهش داده بشه.اما با کمک آپشن پایین به گیت می‌گیم  حتماً یک کامیت آبجکت جدید بساز و کلا از روش fast-forward استفاده نکن.Don&#039;t use fast-forward git-merge, please!آپشن Squashیک آپشن دیگه که توی دستور merge ممکن هست به کارمون بیاد، آپشن پایین هست که باعث میشه همه‌ی تغییرات در قالب یک کامیت اضافه بشه. یکی از کاربرداش هم می‌تونه این باشه که اکثر کامیت‌ها حول یک ویژگی بوده اما به هر دلیلی مجبور شدیم وسط کار کامیت‌های متفاوتی داشته باشم. اما قصد‌مون ادغام همه‌ی کامیت در قالب یک کامیت هست.Summon all commits into one commitمعرفی revertمهم‌ترین ویژگی که باعث میشه ما از ورژن کنترلر استفاده کنیم، قابلیت rollback کردن هست. دستور revert مشابه reset است اما با این تفاوت که revert به عنوان ورودی یک کامیت رو می‌گیره به بجای اینکه به اون وضعيت برگرده، میاد عکس تمام کارهایی که توی اون کامیت انجام شده، رو انجام میده.کاربردش؟ فرض کنید توی یک کامیت یک dependency رو حذف کردیم و می‌خوایم دوباره اون رو داشته باشیم به جای دستی اضافه کردن‌اش، بهتره با revert این کار انجام بشه، چون در قالب یک کامیت به تاریخچه اضافه میشه و دیگران هم می تونن این رو ببینن. یا مثلاً یک کامیت باعث به وجود اومدن باگ شده، و می‌خواید به وضعیت قبلی برگردید؟ جواب کمک گرفتن از git revert هست.What does git-revert do?نحوه استفادهHow to use git-revert commandتوی کامیت‌های بالا، آخرین کامیت رو اگر دقت کنید، Revert بعلاوه پیام کامیت قبلی هست.معرفی cherry-pickاول از همه بد نیست بدونیم cherry-pick به معنی گلچین (سوا) کردن هست و این امکان رو به ما میده که بتونیم کامیت‌های خاصی رو از یک برنچ به برنچ دیگه ببریم. و تفاوتش با git-reset اینه که دستور cherry-pick دقیقا عمل کپی رو انجام میده و باعث حذف چیزی نمیشه؛ در حالی که git-reset کاره‌اش جابجایی اشاره‌گر کامیت‌هاست.کجاها کاربرد داره؟ فرض کنید یکی از همکاران داره توی یک برنچ یک ویژگی جدید به پروژه اضافه می‌کنه و در این حال یک باگ اساسی از سیستم رو هم طی یک یا چند کامیت حل کرده و ما فقط کد بخش حل کردن مشکل رو می‌خوایم. در این حالت اگر merge کنیم همه تغییرات رو اضافه میشه، اما با cherry-pick فقط کامیت‌ مد نظر ما رو به برنچ فعلی اضافه میشه.توی شکل پایین، ما دو تا برنچ داریم (master, feature-branch) و  بر حسب نیاز،‌لازم هست که مثلا کامیت e رو به برنچ master اضافه کنیم:Commits in different branchesروال کار اینجوری هست که اول به برنچ مورد نظر (master) می‌ریم و بعدش هش کامیت e رو به cherry-pick می‌دیم:How to utilize git-cherry-pick معرفی git-rebaseخب، می‌رسیم به شاید یکی از سخت‌ترین یا ناشناخته‌ترین بخش‌های گیت. تا الان یاد گرفتیم اگر بخواهیم تغییرات رو از یک برنچ به برنچ دیگه ببریم تنها راه‌مون git-merge بود. اما یک راه دیگه هم وجود داره که اون git-rebase هست. اگر خاطر‌تون باشه، توی بخش git-merge گفتیم نوع اول مرج fast-forward بود. و این فقط در صورتی قابل انجام بود که گره/جد مشترک نسبت به موقعی که ما برنچ‌مون رو ساخته بودیم تغییر نکرده باشه. در غیر این صورت مرجِ three-way مورد استفاده قرار می‌گرفت.خبر خوب اینه که git-rebase این امکان رو به ما میده که تغییرات رو جوری توی برنچ مورد نظر‌ اعمال کنیم که انگار هیچ تغییری توی مبدا اتفاق نیفتاده و به صورت خطی مرج بشن و و دیگه نیازی به ساخت یک کامیت آبجکت جداگانه نباشه. در حقیقت همون‌طور که از اسمش پیداست داره base برنچ رو (یا بخونید گره/جد مشترک) رو به وضعیت جدید تغییر میده.هدف اینکار بازم تمیز نگه داشتن تاریخچه کامیت‌هاست.مثال پایین از مستندات گیت هست: فرض کنید مطابق شکل پایین یک برنچ master داشتیم و از اون یک برنچ دیگه به اسم experimental ساختیم و توی اون کامیت هم داشتیم. در عین حال، خود برنچِ master هم در این بازه تغییر کرده.Simple divergent historyدر نتیجه اگر بخواهید کامیت کنید، به صورت fast-forward دیگه نمیشه. و خروجی اون یک مرج سه طرفه میشه:Merging to integrate diverged work historyولی اگر هدف ما خطی نگه داشتن تاریخچه کامیت‌ها باشه می‌تونیم با کمک git-rebase این کارو انجام بدیم. این دستور میاد برنچ experimental رو بر میداره و نقطه/جد مشترک‌اش رو به master جدید تغییر میده که شامل کامیت C3 هم هست. خروجی git-rebase این شکلی میشه:Rebasing the change introduced in C4 onto C3حالا اگر دستور git-merge رو بزنیم، گیت به راحتی یه مرجِ از نوع fast-forward انجام میده. ممکن بعضی مواقع conflict هم رخ بده. توی انجور مواقع conflict رو برطرف می‌کنیم و بعدش به rebase با این دستور می‌گید به کارش ادامه بده:git rebase --continueیادتون باشه هرجای rebase می‌تونید از کارتون صرف نظر کنید، با دستور پایین کار شروع شده رو کنسل کنید:git rebase --abortاما دستور اصلی که base برنچ experimental رو به master تغییر داد،‌ این هست:git rebase master experimentalgit rebase &lt;basebranch&gt; &lt;topicbranch&gt;میگن یه قانون طلایی توی git-rebase هست که اگر اون رو رعایت کنید، به رستگاری نزدیک‌تر می‌شید. اونم اینکه هیچ‌وقت روی برنچی که بین شما و همکارات shared هست و اونا دارن باهاش کار می‌کنن rebase نکنید. اینکار اگر آشنا نباشید باعث میشه که کل ایده تاریخچه منظم رو بهم بزنه.همین دستور git-rebase یه آپشن خیلی باحال هم به اسم onto داره که توی شکل زیر به کار میاد.A history with a topic branch off another topic branchمطابق تصویر بالا، مثلاً می‌خوایم برنچ client رو بدون کامیت‌های مشترک‌اش با server ببریم rebaseاش کنیم با برنچ master.در نهایت git-rebase یک آپشن خیلی باحال دیگه هم داره به اسم interactive که با اون میشه‌ تاریخچه کامیت‌ها رو بازنویسی کرد، مثلاً کارهایی مثل Squash یا تغییر پیام کامیت‌ چند کامیت قبل رو هم میشه با این مدل تغییر داد.جمع‌بندیچند وقت پیش من یک ارائه راجعبه گیت داشتم، و در حین ارائه حس کردم مباحثی هست که به خوبی در رابطه با گیت درک نشده، بهمین دلیل توی این دو قسمت (قسمت اول) سعی کردم تا جایی که شدنی هست این مشکلات رو پوشش بدم.در پایان، امیداوارم که از این مطالب چیزی یاد گرفته باشید!از اینجا کجا بریماگر بیشتر می‌خواید راجعبه مرج بدونیدhttps://www.atlassian.com/git/tutorials/using-branches/git-mergeدر رابطه با git-rebasehttps://git-scm.com/book/en/v2/Git-Branching-Rebasinghttps://www.daolf.com/posts/git-series-part-2/در رابطه با git-rebase interactivehttps://thoughtbot.com/blog/git-interactive-rebase-squash-amend-rewriting-history</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Mon, 23 Mar 2020 14:29:22 +0430</pubDate>
            </item>
                    <item>
                <title>مدیریت نسخه برنامه</title>
                <link>https://virgool.io/@GreatBahram/software-versioning-with-bump2version-v99flffjcfib</link>
                <description>https://medium.com/better-programming/why-versioning-is-important-and-how-to-do-it-686ce13b854fمقدمهیک‌چالشی که من باهاش روبرو شدم مدیریت نسخه‌های پروژه‌های مختلف بود و نیاز به ابزاری داشتم که هم راحت‌باشه که همه ‌راحت یادش بگیرن و هم اینکه بخشی از کار رو خودکار کنه. این پست اشتراک ابزاری هست که واسه حل این مشکل استفاده کردم.به این فرایند که به یک state از برنامه‌مون یک شماره یا اسم خاص تخصیص می‌دیم Versioning گفته میشه.برای مدیریت version برنامه، چندین مدل مرسوم وجود داره، که شناخته ترین اونا این‌ها هستند:Semantic VersioningCalendar Versioningتقریبا همه‌ی روش‌های بالا از سه بخش اصلی {patch/micro}{minor}{major} پشتیبانی می‌کنن. توی روش Calender معمولاً major نشون دهنده سال و minor ماه انتشار برنامه رو نشون می‌ده. از پروژه‌های مرسوم که از این روش پیروی می‌کنن میشه به توزیع گنو/لینوکس اوبونتو، پروژه Twisted یا پکیج‌منجر پایتون pip اشاره کرد:روش Semantic هم چیزی هست که معمولاً همه‌جا می‌بینیم و خیلی شاید نیازی به توضیح اون نباشه، مثلاً 3.7.5.اما مشکلی که دیر یا زود گریبان همه ما رو می‌گیره مدیریت نسخه‌‌‌هاست وقتی تعداد پروژه‌ بالا میره. اینجور مواقع دیگه نیاز دارید که خیلی راحت‌تر بتونید نسخه برنامه رو جلو ببرید یا به عبارت دیگه این کار تا حدی automatic بشه. یکی از پروژه‌های خوبی که به ما می‌تونه کمک کنه bump2version هست (این نسخه جدیدتر پروژه bumpversion هست).نصبخب حالا که نصب شده، کافیه واسش current_version رو مشخص کنید و بعد هر موقع خواستید نسخه رو ببرید جلو بهش بگید که مثلاً major، minor یا patch رو یک نسخه جلو ببره. مثلا، توی پروژه‌ی پایین ما چند جای مختلف از متغییر version استفاده کردیم و هر بار هم بخوایم یک نسخه جلو بریم باید دستی این کار رو انجام بدیم.اما با کمک این ابزار میشه اینجوری این معضل رو حل کرد (نسخه فعلی رو واسش مشخص کردیم و بهش‌ گفتیم که قصد داری بخش patch رو افزایش بدیم):یک امکان باحال‌تر این پروژه اینِ که می‌تونید کنار پروژه‌تون یک فایل کانفیگ بذارید و توی اون نسخه‌ی فعلی رو مشخص کنید و بعدش می‌تونیم کار تغییر رو به برنامه bumpversion بسپاریم:با کانفیگ بالا،‌نه تنها نسخه رو برای مدیریت می‌کنه بلکه خودش کامیت رو هم انجام می‌ده ولی ازش خواستیم که تگ نزنه.یک قاعده کلی هم میشه راجعبه Major، Minor و Patch گفت:هر موقع ما یک باگ رو اصلاح می‌کنیم انتظار میره که Patch رو جلو ببریم. وقتی یک قابلیت جدید به برنامه‌مون اضافه می‌کنیم که با نسخه‌های قبلی سازگار هست، سراغ Minor می‌ریم.و نهایتاً وقتی برنامه تغییرات زیادی می‌کنه که سازگاری با نسخه‌های قبلی دیگه وجود نداره توسعه‌دهنده‌ها Major رو تغییر میدن. برای اطلاعات بیشتر در این رابطه خوبه مستندات خود SemVer رو بخونید. جمع‌بندیامیدوارم از این مطب کوتاه چیزی مفیدی عایدتون شده باشه!</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Sat, 07 Dec 2019 17:01:03 +0330</pubDate>
            </item>
                    <item>
                <title>یک‌بار برای همیشه - گیت 1</title>
                <link>https://virgool.io/@GreatBahram/demystifying-git-internal-once-for-ever-v0gp0padsyjn</link>
                <description>Post logoمعرفیتوی این سری قصد داریم، راجعبه گیت صحبت کنیم. و فرض‌مونم اینِ که تا حدودی (تقریباً متوسط) با گیت آشنا هستید و با یک سری از مفاهیم پیچیده گیت مساله دارید.توی این مطلب، قصد داریم تا جایی که میشه روند ذخیره‌سازی و مدیریت فایل‌ها توسط گیت رو بررسی کنیم. برای این‌کار سری به فایل‌ها و آبجکت‌هایی که گیت استفاده می‌کنه می‌زنیم.مقدمهتمام کارهای باحالی که گیت انجام میده داخل یک دایرکتوری خاص انجام میشه که اسمش git. هست. وقتی شما یک پروژه رو با گیت ایجاد می‌کنید این دایرکتوری به پروژه شما اضافه میشه و زیرساخت‌های لازم، واسه گیت رو فراهم می‌کنه:How does git change our working directory?میشه اینجوری هم گفت که داشتن این دایرکتوری این امکان رو به ما میده که تمام فایل‌های دیگه‌ای که گیت مدیریت می‌کنه رو از روی  اون بسازیم(بازیابی کنیم) و حذف این دایرکتوری هم مساوی هست با حذف تمام تاریخچه‌ی کامیت‌ها!اول از همه، می‌خوایم ببینیم داخل این دایرکتوری چه فایل‌های وجود داره و کاربرد هر کدوم‌شون چی هست:Let&#039;s examine content of .git directory!خب از چیزهای راحت شروع کنیم:فایل description که یک متن داخل اون وجود داره و برای نمایش توی وب استفاده میشه. مثل متن پایین که هایلات شده:The purpose of description file.فایل config، که تنظیمات مربوط به پروژه رو برای شما نگه‌داری می‌کنه (Project specific configuration). به صورت پیش‌فرض مقادیر زیر رو داره:The default content of .git/config fileدایرکتوری info، یک فایلی داره به اسم exclude که دقیقا مشابه gitignore. فایل هست و امکان جلوگیری از track کردن گیت از اون فایل‌ها یا patternها رو میده. فرق‌اش با gitignore. توی این هست که توسط گیت track نمیشه یا جایی نمیشه share اش کرد.دایرکتوری hooks: اینجا می‌تونیم یک‌سری اسکریپت به گیت معرفی کنیم که قبل/بعد از یک عمل خاص اجرا بشن. مثلاً قبل از هر کامیت چک کنیم که متن کامیت خالی نباشه. خود گیت‌ هم چندین sample داخل این دایرکتوری داره و احتمالاً در آینده یک مطلب راجعبه این بخش خواهیم داشت:List of built-in git hooksفایل HEAD: که در حالت نرمال به branch فعلی اشاره می‌کنه، اگر محتواش رو چک کنیم:Let me see you Head!چیزی که از متن بالا میشه فهمید، این هست که خود HEAD یک اشاره‌گر به یک فایل دیگه هست و آدرس اون فایل داخل HEAD قرار داره. اگر بریم اون مسیر رو بررسی کنیم:I want to see inside of youگیت خطا میده، چون که ما توی این مخزن هیچ کامیتی نداشتیم، اگر یک کامیت به این برنچ اضافه کنیم:What Git does after committing a single-empty file.می‌بینیم که داخل اون فایل، هشِ یک کامیت ذخیره شده.نتیجه‌گیری: فایل HEAD در حالت نرمال به branch فعلی ما اشاره می‌کنه و برنچ فعلی ما هم یک اشاره‌گره به آخرین کامیت هست و هر بار که یک کامیت به مخزن استفاده کنیم این متن با متن جدید جایگزین میشه. میشه هم نتیجه گرفت که برنچ‌ها یک اشاره‌گری هستند که همیشه قابل بروزرسانی/جابجایی هستند.در ادامه دایرکتوری objects رو بررسی می‌کنیم.بررسی کامیتاحتمالا این گزاره رو شنیدید که گیت برخلاف ورژن کنترلرهای دیگه تغییرات رو ذخیره نمی‌کنه بلکه در هر کامیت، یک اسنپ‌شات از کل فایل ها رو نگه می‌داره.Contrast Subversion and Gitمطابق عکس بالا (که یک ورژن کنترلر متمرکز رو با گیت مقایسه کرده)، گیت تفاوت‌ها در هر نسخه ذخیره نکرده، بلکه در هر کامیت دقیقا خود فایل ذخیره شده. در حقیقت هر بار که شما یک تغییری توی فایلها ایجاد می‌کنید و کامیت می‌کنید، دو کار اتفاق میفته:اول گیت چک می‌کنه و اگر چیزی تغییر کرده باشه، اون رو فشرده می‌کنه و اون رو داخل دایرکتوری objects ذخیره میکنه و  اسم اون (که معادل همون هش‌اش هست) به اسنپ‌شات اضافه میکنه و نهایتاً خود این اسنپ‌شات هم فشرده سازی میشه و به اون یک هش برای ارجاع دادن (رفرنس) اختصاص داده میشه.اگر هم فایلی تغییر نکرده باشه، گیت هش قبلی اون فایل رو توی اسنپ شات فعلی ذخیره می‌شه. تا دیگه نیازی به ذخیره مجدد اون نباشه.خب بریم دایرکتوری objects رو با هم چک کنیم:Examine .git/objects directoryاین حاصل کاری هست که گیت فقط برای اضافه کردن یک فایل انجام داده. اما ما فقط یک فایل اضافه کردیم چرا سه تا هش اینجا وجود داره؟بررسی آبجکت‌های گیتگیت یک فایل‌سیستم برای خودش داره، توی ادبیات اون به جای دایرکتوری گیت از یک آبجکت به اسم tree استفاده می‌کنه. داخل هر tree یا treeهای دیگه‌ قرار دارند یا یک‌سری فایل هست، دقیقا مشابه دایرکتوری. و همین‌طور برای ذخیره‌سازی فایل از یک آبجکت به اسم blob استفاده می‌کنه. گیت آبجکت‌های دیگه‌ای هم داره:آبجکت commit که به یک tree اشاره می‌کنه (دایرکتوری اصلی پروژه) و نشون میده که در اون لحظه محتوای پروژه به چه صورت بوده و  یک سری metadata هم داخل اون برای ذخیره سازی پارامترهایی مثل اسم commiter و زمان و اشاره‌گری به کامیت‌های قبلی استفاده میشه.آبجکت tag که برای اسم‌گذاری یک کامیت خاص به کار می‌ره و معمولاً برای اسم‌گذاری releaseهای مختلف ازش استفاده میشه.اگر بخواهیم از دید گیت به مخزن‌مون نگاه کنیم، دستور git ls-tree این امکان رو به ما میده:Output of git ls-tree master .خروجی بالا به ما نشون می‌ده که تا الان فقط یک فایل (blob) داشتیم. اگر پروژه‌ی ما شامل یک دایرکتوری (tree) هم بود، گیت اون رو اینجوری ذخیره می‌کرد:What object git uses to save a directoryاحتمالا، شما می‌دونید که گیت برای هش گرفتن از sha1 استفاده می‌کنه، اما اگر سعی کنید هش اون رو خودتون با sha1 بگیرید می‌بینید که خروجی‌شما با گیت متفاوت هست. این به این دلیل هست که گیت به ابتدای اون یک‌چیزی هم اضافه می‌کنه:Generate sha1 checksum similar to gitبرای کنجکاوی بیشتر می‌تونیم به دایرکتوری objects بریم و از خود گیت بپرسیم که هر آبجکت اونجا نماینگر چه چیزی هست. اما قبل از اینکه‌ این کار رو بکنیم بذارید یک جمع‌بندی از ساختار فعلی‌مون داشته باشیم. توی مخزن ما، یک دایرکتوری اصلی  (test_git) داریم که توی اون فقط یک فایل خالی وجود داره و فقط هم یک‌ کامیت داریم. در نتیجه گیت باید همه‌ی اینارو الان داشته باشه:Determine type of each git objectوقتی لیست آبجکت‌های رو با کمک find می‌گیریم سه آبجکت اونجا حضور داره. بنظر می‌رسه که همه‌چی همون‌جوری که حدس می‌زدیم هست. فقط ممکن هست متوجه این نکته بشید که هش ها به دو بخش تقسیم شدن، دو کاراکتر اولش اسم دایرکتوری شده و مابقی اسم اون آبجکت مورد نظر هست. دلیل این کار هم این هست که اکثر فایل‌سیستم‌ها به شما اجازه ذخیره بیش از مقداری رو نمی‌دن و اگر گیت این کار رو نمی‌کرد خیلی زود با فایل‌سیستم‌ِ  (هر؟) سیستم‌عاملی به مشکل می‌خورد.فراموش هم نمی‌کنیم که تمام فایل‌های داخل این دایرکتوری به صورت فشرده ذخیره شدن:We shouldn&#039;t forget that there are compressedبرای اینکه بتونیم محتوای این آبجکت‌ها رو ببینیم، بهترین ابزار دستور cat-file هست، که با آپشن t- امکان تشخیص نوع اون آبجکت رو به ما میده.آخرین کنجکاوی ما بررسی ساختار یک کامیت هست. هر کامیت هم باید مشخص کنه داخل کدوم دایرکتوری (tree) قرار داره و باید مشخص باشه که چه کسی اون نویسنده و committerاش کی بوده و در آخر باید یک متن کامیت هم داشته باشه.با کمک ابزار cat-file محتوای آبجکت commit رو بررسی می‌کنیم:What&#039;s going on inside git commit object!به نظر می‌رسه هر کامیت، مشخصات خودش رو می‌دونه به همراه آدرس یک tree که داخل اون فایل‌های مربوط به قرار دارند.یک جمله‌ی اول این پست گفتیم که گیت در هر کامیت یک snapshot از فایل‌ها داره نه diff اونا. بیاید این رو هم با هم دیگه چک کنیم.برای این‌کار هم دو کامیت به مخزن بالا اضافه می‌کنیم.اول محتوای فایل اول‌مون رو تغییر می‌دیم:Change is always good, as nature does it all the time!بعدش یک فایل‌ دیگه به مخزن‌مون اضافه می‌کنیم.حالا باید توی کامیت کامیت سوم، فایل first_file دوباره ذخیره نشده باشه یعنی توی کامیت سوم هش first_file وجود داشته باشه، ثانیاً چیزی شبیه خروجی diff نباید ببینیم بلکه محتوای خود فایل باشه. پس تا الان سه تا کامیت داریم:List of commits in our projectپایین حاصل بررسی این دو کامیت و محتوای tree هر کدوم رو می‌بینیم:Lets get deep into two different commit objectsاگر دقت کنیم می‌بینیم که هش first_file توی هر دو تا tree یکی هست و محتوای blobها هم به شرح زیر است:Compare content of two differentآبجکت تگحالا که پروژه‌مون حسابی بزرگ شده، بیاید یگ تگ هم بهش بزنیم. تگ‌های راهی ساده برای اسم‌گذاری کامیت‌ها هستند و اکثر توسعه‌دهنده ها از اون برای مشخص کردن هر release استفاده می‌کنند.Tag our projectبه محض اجرا شدن، دستور بالا گیت یک اشاره‌گر (رفرنس) می‌سازه که داخل اون هش کامیت مورد نظر رو نگه داری می‌کنه:همین‌طور گیت یک آبجکت جدید داخل دایرکتوری git./objects اضافه می‌کنه که این آبجکت اطلاعات لازم راجعبه اون تگ رو مثل چه کسی تگ‌اش کرده، تگ به کدوم کامیت بوده و ... رو نگه‌داری می‌کنه:How git saves a tag objectبنظر می‌رسه تگ‌ها مشابه برنچ‌ها هستند. دو‌تاشون یک اشاره‌گر به کامیت مورد نظر دارند. با این تفاوت که تگ‌ها بر خلاف‌ برنچ‌ها امکان جابجایی یا به روزرسانی ندارند.جمع‌بندیهدف از این مطلب، افزایش درک ما نسبت به روند کار گیت بود و یاد گرفتیم که گیت محتوای ما رو فشرده می‌کنه و برای ارجاع به هر چیزی از تابع هشِ sha1 استفاده می‌کنه. همین‌طور دیدیم که گیت چطور با استفاده از چهار آبجکت این کار رو انجام میده. آبجکت tree که معادل همون دایرکتوریِ و آبجکت blob که گفتیم برای ذخیره سازی محتوای فایل‌های به کار می‌ره و آبجکت commit رو دیدیم که اطلاعات هر کامیت رو نگه داری می‌کرد و نهایتاً آبجکت tag رو در آخر با هم بررسی کردیم.بروزرسانیاز اینجا می‌تونید قسمت دوم این سری رو هم بخونید که بیشتر به مباحت نسبتا پیچیده گیت پرداخته شده و طبق معمول هدف‌مون هم توضیح  او مسائل به زبان ساده هست.امیدوارم که از این مطلب چیزی یاد گرفته باشید و اگر خوش‌تون اومده اون رو با دوستان و همکارای خودتون به اشتراک بذارید.از اینجا کجا بریم؟اگر علاقه‌مند هستید که بیشتر راجعبه مباحث بالا بدونید، داکیومنت‌های خود گیت بهترین مرجع توی این حوزه هستند:Git Objectsاگر این برای شما سوال هست که ذخیره کردن کل فایل در مقابل Changesetها کدوم‌اش موثرتر هست، لینک پایین شروع خوبی می‌تونه باشه:How does git store files?من راجعبه گیت یک ارائه داشتم، اسلاید‌های این ارائه هم در آدرس پایین قابل دسترسی هست:Git tutorial slides</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Tue, 12 Nov 2019 17:02:42 +0330</pubDate>
            </item>
                    <item>
                <title>موثرتر کار کنیم - Black</title>
                <link>https://virgool.io/@GreatBahram/python-black-code-formatter-kywenwjhivcs</link>
                <description>The uncompromising Python code formatterمقدمهسلام،هدف‌مون از سری «موثرتر کار کنیم» این هست که بتونیم زمان‌مون رو از کارهای زمان‌گیر و کم‌عمق - که امکان automate کردن‌شون وجود داره - برای کارهای مهم‌تر ذخیره کنیم. توی این قسمت می‌خوایم با یک ابزار خیلی خوب آشنا بشیم که نگرانی ما رو نسبت به کد استایل‌مون کمتر کنه و زمان‌ بدست اومده رو ببریم جای‌ مهم‌تری به کار ببریم.معرفیپایتون به خاطر سادگی‌اش خیلی از آدم‌ها رو به خودش جذب می‌کنه. اما یک مساله‌ای که وجود داره این هست که با وجود داکیومنت‌ خوبی مثل PEP8 بازم بین توسعه‌دهنده‌ها اختلاف نظر زیادی، راجعبه کد‌استایل، وجود داره.به‌ همین خاطر ابزارهای مختلفی برای این کار ساخته شدند که یک گزارش راجعبه بخش‌هایی که کداستایل فایل مطابق با PEP8 نبوده می‌دن.مثلاً فلان‌جا باید newline به کار بره و مثال‌های مختلف دیگه‌ای که باهاشون آشنا هستیم.از این دسته از ابزارها میشه به پروژه‌های زیر اشاره کرد:pycodestyleflake8...یک نکته‌ای که خوب هست بهش اشاره کنیم، اینه که توی Editor‌های جدید این ابزارها با Editor یکپارچه (integrate) شدن به‌ همین خاطر هست که معمولاً پایین IDE یک سری خطاها به شما اعلان میشه.ولی چی می‌شد که اگر یک Code Formatter وجود داشت که خودش فایل رو می‌گرفت و مشکلات رو هم خودش برطرف می‌کرد؟مهم‌ترین ویژگی‌ای این برنامه‌ هم قطعی بودن deterministic هست. یعنی فارغ از اینکه چندبار روی یک پروژه اجراش کنیم همیشه یک خروجی یکسان به ما بده. اینجوری خیلی قابل اتکاتر میشه!«بروزرسانی شده»به این دسته از ابزارها که کد رو به عنوان ورودی می‌گیرند و سعی در درست کردن فرمت اون می‌کنند اصطلاحاً Auto code formatter گفته میشه.از Auto code formatter های بنام پایتون میشه به موارد زیر اشاره کرد:autopep8yapfBlackما توی این سری، تصمیم گرفتیم که فقط به Black بپردازیم، چون تقریباً ویژگی که می‌خواهیم رو داره و بنظر من سادگی Black کار با اون رو راحت‌تر و دلچست تر می‌کنه.Black Logoاستفاده از Blackمثل همیشه اول باید نصب‌اش کنیم:برای استفاده از بلک باید حداقل از پایتون ۳.۶ استفاده کنید.خب حالا یک برنامه به Command-line‌تون اضافه شده که می‌تونید ازش استفاده کنید، فرض کنید قطعه کد پایین رو داریم و می‌خوایم ببنیم بلک چجوری می‌تونه به ما کمک کنه:خب، حالا کافیه به بلک بگیم که فایل ما رو اصلاح کنه:خروجی بالا، به ما میگه که بلک فایل ما رو reformat کرده (به صورت پیش‌فرض بلک فایل‌های شما رو تغییر میده، مگر اینکه بهش بگید اینکار رو نکنه!).خب، حالا ببنیم که کد‌مون چه تغییری کرده:احتمالاً شما هم متوجه این می‌شید که سازنده‌های بلک علاقه‌ زیادی به استفاده از double-quotation داشتند.بلک، یک آپشن خیلی خوب هم داره که باعث میشه فقط کد رو بررسی کنه و اگر چیزی برای تغییر باشه، خطا بده و بره بیرون. این ویژگی باعث میشه بتونیم بلک‌ رو به ابزارهای CI به راحتی وصل کنیم.اگر هم نیاز دارید که اول ببینید بلک قرار هست با فایل ورودی چیکار کنه، می‌تونید به صورت پایین ازش استفاده کنید:بلک خیلی به راحتی می‌تونه به Editorهای مختلف وصل بشه و تقریبا داکیومنت جامعی برای این کار داره و یه خبر خوب دیگه این هست که یک magic command هم هست که باعث میشه بتونیم تویJupyter Notebook هم ازش بتونیم استفاده کنیم.جمع‌بندیبلک ممکن هست یکم با چیزی که توی ذهن‌ ما راجعبه استاندارد بودن کد‌استایل داریم متفاوت باشه؛ اما روی هم رفته صرف نظر کردن از چند مورد مخالفت ساده، ارزش رسیدن به یک چیز جامع رو داره!اما بلک تا حدودی قابل کانفیگ هم هست، فقط باید یادمون نره که هدف بلک این هست که به یک فرمت جامع بین افراد مختلف برسیم پس انتظار چیزه خیلی پیچیده‌ای از این configuration نباید داشت. در پایان، کد استایلِ کد مهم هست، اما کاری است زمان‌بر، پس تا بلک هست بذاریم اون انجامش بده!از اینجا کجا بریماگر به دنبال مقایسه بلک با ابزارهای مشابه هستیدhttps://medium.com/3yourmind/auto-formatters-for-python-8925065f9505https://news.ycombinator.com/item?id=17155048</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Sat, 12 Oct 2019 14:48:51 +0330</pubDate>
            </item>
                    <item>
                <title>معرفی __new__</title>
                <link>https://virgool.io/@GreatBahram/constructor-method-in-python-otgdovgvnucf</link>
                <description>A gentle introduction to __new__مقدمهتوی این قسمت، خیلی سریع و خلاصه می‌خوایم متد __new__ رو معرفی کنیم و به کاربردهای اون اشاره کنیم.معرفیبرای ساخت یک Instance از کلاس دو متد اصلی هستند که اجرا می‌شن. هر کدوم هم کار متفاوتی انجام میدن.متد __new__: این متد، که خیلی کمتر مطلب بهش پرداخته شده، قبل از __init__ اجرا میشه و معمولا اگر قصد انجام کار خاصی رو نداشته باشید، نیازی به نوشتن‌اش نیست.متدی هم هست که آبجکت رو می سازه. نکته آخر اینکه این متد به صورت پیش‌فرض Static method هست و نیاز هم داره که پارامتر اول اون همیشه cls باشه.متد __init__: این که خیلی ممکن هست اون رو متد سازنده (Constructor) توی پایتون بدونند، واقعاً نقش‌اش initializer رو بر عهده داره .حالا برای روشن شدن مطلب می‌ریم اولش static method رو تعریف کنیم و بعدش به خود متد __new__ می‌پردازیم.معرفی Static Methodاین مفهوم در مقابل مفهوم دیگه‌ای به اسم instance variable قرار می‌گیره. تو مثال زیر متد و attributeهای ما instance variable هستند.کاری که کردیم این هست که یک instance از کلاس Math ساختیم و از تابع add استفاده کردیم. اما چی میشه اگر ازش Instance نسازیم و بخوایم ازش استفاده کنیم؟خطا بالا داره میگه که انگار یک پارامتر کمتر به تابع add دادیم و بهمین خاطر معترض شده! بیایم instance رو دستی بهش پاس بدیم:همم، پس اینجوری خوشحال‌تر شد. پس instance variableها بدون داشتن یک instance قابل استفاده نیستند.اما می‌تونیم خوشحالی کلاس Math رو یک سطح هم بالاتر ببریم اگر کلا این متد رو جوری تعریف کنیم که نیاز به Instance ای نداشته باشه و امکان استفاده بدون ساخت Instance هم وجود داشته باشه.اینجا با کمک دوست خوب‌مون staticmethod - که یک property ( یا به اصطلاح درست‌تر یک Descriptor) هست - به پایتون می‌گیم که نیازی نیست که instance اولین پارامتر ما باشه. در نتیجه بدون ساخت instance می‌تونیم ازش استفاده کنیم.حالا چی مشه، اگر از اون یک Instance بسازیم؟ آیا باز هم قابل استفاده هست؟به عنوان جمع‌بندی این بخش، ما به صراحتاً به پایتون گفتیم که این متد به صورت static method به کارش ادامه بده، اما بعضی توابع خاص (Magic methods) به صورت پیش‌فرض static method هستند، مثل __new__.معرفی __new__وقتی می‌گیم که __init__ تابع سازنده نیست به این خاطر هست که شما داخل __init__ به آبجکت دسترسی دارید. نشون به این نشون که:همین نشون میده که انگار یک‌جای دیگه instance ما ساخته شده (چون پایتون خطا نداد که self وجود نداره!).نکته اول: میشه اینجوری هم گفت که هرکجا instance ما ساخته میشه، دیگه امکان استفاده از self وجود نخواهد داشت.نکته دوم: با توجه به نکته یک میشه فهمید چرا __new__ به صورت پیش‌فرض staticmethod هست.نکته سوم: instanceها وقتی ساخته می‌شن که شما class رو call می‌کنید مثل Music(&#x27;Disturbia&#x27;).وظیفه‌ی متد __new__ این هست که instance رو برگردونه اگر این متد چیزی رو برنگردونه متد __init__ هم اجرا نمیشه. و نهایتاً اینکه __new__ همه‌ی پارامتر‌هایی که شما به کلاس‌تون پاس می‌دید رو میبینه و بعلاوه یک چیزه اضافه‌تر که جلوتر می‌بینیم.یک نمونه با هم ببینیم:با توجه به خروجی بالا، میشه فهمید که cls همون‌ کلاسی هست که قرار از روی اون یک instance ساخته بشه و مابقی هم پارامتر‌هایی هستند که از ورودی دریافت کردیم. همون‌طور که گفتیم اگر چیزی داخل __new__ برنگردونیم (return)، متد __init__ اجرا نمیشه، در نتیجه توی مثال بالا سه خط آخر اصلا اجرا نشده‌اند.اگر بخواهیم رفتار نرمال متد __new__ رو نشون بدیم چیزی شبیه پایین میشه:اینجا چه اتفاقی رخ داده؟ ما از سوپرکلاس‌مون خواهش کردیم که به جای ما یک instance بسازه و همچنین به صورت dynamic یک attribute به instance تازه ساخته شده اضافه کردیم (created_at).کاربردهاچه مواقعی نیاز داریم که __new__ رو override کنیم؟جواب.یک مثال عملی رو با هم ببینیم و بحث رو تموم کنیم. اگر با ایده‌ی Singleton آشنا باشید می‌دونید که هدف اون ساخت کلاسی هست که فقط امکان ساخت یک instance ازش وجود داشته باشه. برای پیاده‌سازی این مفهوم روش‌های مختلفی هست اما ما عمداً با کمک متد __new__ این مفهوم رو پیاده‌سازی می‌کنیم:اینجا متد سازنده رو طوری تغییر دادیم که - عمداً - فقط بتونیم یک instance از کلاس‌مون بسازیم و هربار که تلاش کنیم چیز جدید بسازیم همون قبلی رو برگردونه.اگر مثال یا تجربه شخصی استفاده از متد __new__ دارید اون رو حتماً با ما به اشتراک بذارید.کلام آخرامیدوارم که از این مطلب خوشتون اومده باشه و چیزی ازش یاد گرفته باشید، اگر این‌طور بوده حتما این مطلب با پایتون دوست‌های دیگه به اشتراک بذارید. فعلاً!</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Wed, 09 Oct 2019 07:53:07 +0330</pubDate>
            </item>
                    <item>
                <title>یک‌بار برای همیشه - Property</title>
                <link>https://virgool.io/@GreatBahram/once-for-all-property-sovwcuakw7aq</link>
                <description>What is property in Python?مقدمهسلام به همه دوست‌داران پایتون!امروز هدف‌مون این هست که یک موضوع خیلی ساده اما کاربردی رو با هم بررسی کنیم. یک مفهومی توی پایتون وجود داره که خیلی مشابه با زبون‌‌های برنامه نویسی دیگه هست. اما خب مثل همیشه انتظار داریم یکم باحال‌تر هم باشه.اول از همه، باید یادآوری کنیم که پایتون برخلاف زبان‌های برنامه‌نویسی دیگه به ما اجازه دسترسی مستقیم به attribute ها رو میده. دسترسی مستقیم به attributeها در پایتونمگه حالت دیگه‌ای هم هست؟ بله! حالتی که شما برای دسترسی به ویژگی‌/attributeها نیاز به یک واسط داشته باشید که عموماً این واسط‌ها تحت نام Setter/Getter شناخته می‌شن، چیزی شبیه قطعه کد پایین:دسترسی غیر مستقیم به attributeها در پایتونخب، بنظر می‌رسه که پایتون با این ترفند، کار ما رو بسیار راحت کرده. اما!اما چی میشه اگر ما واقعاً به این واسط‌ها نیاز داشته باشیم؟یا شاید بهتر باشه اول بگیم که چرا ممکنِ به این‌ واسط‌ها اصلا نیاز داشته باشیم؟حالت اول، تصور کنید نیاز داریم که هر موقع به اسم کتاب دسترسی داشتیم، حرف اول هر کلمه بزرگ به ما تحویل داده بشه، به توابعی از این جنس، Getter گفته میشه (چون‌که داریم یک چیز رو می‌گیریم) و عموماً هدف‌ توسعه‌دهنده می‌تونه کارهای از جنس Normalization و یا Validation باشه.حالت دوم، فرض کنید هدف‌مون این هست که اسم کتابی رو که کاربر وارد کرده بررسی کنیم که حاوی کاراکتر‌های فارسی نباشه. این کار توسط توابعِ Setter انجام میشه (چون‌که داریم یک مقدار رو توی attribute ذخیره می‌کنیم) و اکثر مواقع داخل این توابع کارهای محاسباتی انجام میشه.حالت آخر، توابعی هستند که برای delete کردن یک attribute به کار می‌رن، به طور مثال ممکن هست نخواهیم اجازه بدیم کاربر بتونه اسم کتاب رو حذف کنه. اسم این توابع Deleter هست.یکم کد بزنیمبرای ساختن setter/getter توی پایتون از property کمک می‌گیریم. اولین قدم این هست که یک متد رو تعریف کنیم و این متد به عنوان Getter هست یا برای دریافت attribute مورد نظرمون (بقیه موارد setter/deleter به صورت اختیاری هستند).Firstly, define your methodبعد از تعریف متد، تنها کاری که لازم هست انجام بدیم اینه که از property decorator استفاده کنیم و پایتون مابقی کار رو برای ما انجام میده (اگر با decorator آشنا نیستید، پیشنهاد می‌کنم این پست رو بخونید).Then add property decoratorاگر به مثال بالا دقت کنید،‌ در حالی که name به صورت متد تعریف شده، اما property کاری کرده که انگار داریم با یک attribute کار می‌کنیم.نحوه‌ی تعریف setter هم به صورت پایین هست:How to use setter with propertyمثال دومفرض کنید که ما یک کلاس داریم به اسم Person که هدف‌مون این هست بعد‌ از اینکه اسم کاربر رو گرفتیم اون رو به صورت lowercase ذخیره کنیم و داده‌ی غیر از string قبول نکنیم. طبیعتا این کارها باید توسط setter انجام بشه.Example 02تا اینجای کار، میشه گفت property رفتار یک متد رو به نحوی تغییر میده که کاربر فکر می‌کنه داره با یک ویژگی/attribute کار می‌کنه. به عبارت خیلی ساده‌تر موقع اجرای متدمون نیازی به گذاشتن () نیست.از مهم‌ترین مزیت این کار هم میشه به ملموس شدن یا منطقی شدن کد برای استفاده‌ کننده‌ها اشاره کرد.دقت کنید، قرار نیست ما کاری بکنیم که متد‌ها به صورت attribute قابل دسترسی باشند! بلکه هدف اینه که کارهای محاسباتی و validation که مخصوص یک attribute هستند رو با خود attribute یکی کنیم. از دید کاربر پنهان‌شون می‌کنیم. به عبارت دیگه داریم دسترسی مستقیم رو از کاربر می‌گیریم.کد‌های قدیمیهمه‌ی ما ممکنه که به کد‌های قدیمی بر بخوریم و شاید مهم‌ترین نکته‌ی که باید بهش توجه کنیم این باشه که تغییرات ما باعث شکنندگی کد نشه (Backward compatibility رو حفظ کنیم). حالا فرض کنید قطعه کدی داریم که توسعه‌دهنده setter/getterها به صورت پایتونیک ننوشته و از طرفی ما نمی‌خوایم اینقدر کد تغییر پیدا کنه که برنامه‌های وابسته به اون از کار بیفتند. راه حل چیه؟راه حل دوباره property هست. property رو به دو حالت میشه استفاده کرد: حالت اول که حالت خیلی خوبش بود (چیزی که شما همیشه باید از اون استفاده کنید) استفاده از property decorator بود. اما حالت دومی هم وجود داره که به صورت زیر هست:Property in other wayبا این حالت نه تنها متد‌های قبلی به کارشون ادامه بدن و بلکه ما می‌تونیم با propertyی name به هدف‌مون (پایتونیک) برسیم.خستگی سلاممثل همه‌ی چیزهای کره‌زمین property هم اونقدر کامل نیست و بعضی اوقات خیلی کسل‌کننده میشه. فرض کنید هدف‌مون این هست که یک کلاس برای ذخیره کردن اطلاعات مربوط به فیلم‌ داشته باشیم‌، چیزی شبیه پایین:Movie objectاگر به کد دقت کنید، می‌بینید که چهار از attributeهای ما قرار هست که مقدار int بگیرند. از قضا، هیچ‌کدوم از اینا نمی‌تونن مقدار کمتر از صفر (منفی) بگیرند. خوشبختانه ما روش حل این مساله رو بلدیم. کلید حل مساله استفاده از property هست، کافیه هر کجا مقدار منفی خواست وارد بشه ، سریع خطا بدیم:Use property to solve the problemهمه‌چی ممکن است در نگاه اول خوب بنظر برسه، اما یک مشکلی اساسی توی این کد وجود داره و اون این هست که تکرار کد بشدت بالاست (Repetition). درسته که ما کارمون رو به درستی انجام دادیم و جلوی مقدار منفی رو گرفتیم؛ اما عملاً یک کار رو چهار بار تکرار کردیم.و خب طبق معمول، حتما باید راه بهتری برای انجام این کار باشه ?.مثلا، اگر به شکل زیر پیاده‌سازی می ‌شد، چی:Let the magic happensتوی قطعه کد بالا ما با استفاده از یک مکانیسم داریم رفتار attributeها رو مدیریت می‌کنیم. به این ساز و کار descriptor گفته میشه.تا اینجای کار به هیچ عنوان property رو تعریف نکردیم؛ بلکه کارکردش رو مرور می‌کردیم، اما واقعیت این هست که property یک نوع descriptor محسوب میشه. تو مواردی مشابه مثال بالا، ما نیاز داریم بریم ساز و کار خاصِ خودمون رو پیاده‌سازی کنیم تا به اون چیزی که می‌خوایم برسیم (NonNegative).جمع‌بندیپس تا الان متوجه شدیم که property ها functionality خیلی عجیبی به برنامه‌ی ما اضافه نمی‌کنند فقط به ما امکان مدیریت بیشتر روی attributeها رو برای ما فراهم می‌کنند.یک امکان دیگه‌ی که propertyها به ما میدن و اینجا خیلی راجع‌اش صحبت نشد، lazy loading هست. یعنی محاسبات انجام نمی‌شن تا وقتی که نیاز بشن. دلیل این‌کار هم بنظرم دیگه الان برای شما واضح هست، چون property در حقیقت دارن یک متد رو اجرا می‌کنند و درنتیجه تا اجرا نشن، محاسباتی هم نیز صورت نمی‌گیره.توی قسمت بعدی هدف‌مون بررسی و ساخت descriptor هست.از اینجا کجا بریماگر بازم دوست دارید راجعبه property بدونید، دو لینک پایین می‌تونن به شما کمک کنند.Python 101Python decorator and propertyبنده در تاریخ بیست‌ و ششم اردیبهشت ۱۳۹۸ در گروه کاربران پایتون تهران راجعبه همین موضوع یک ارائه داشتم و فایل‌هایی که اونجا استفاده شد رو توی لینک پایین می‌تونید پیدا کنید.TehPUG - Property</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Thu, 30 May 2019 16:44:22 +0430</pubDate>
            </item>
                    <item>
                <title>پایتونیک - برابری یا هویت مساله این است!</title>
                <link>https://virgool.io/@GreatBahram/equality-vs-identity-hsypqwrjx6rr</link>
                <description>مقدمهسلام، امیدوارم که مثل همیشه خوش و خرم باشید. درمجموعه پایتونیک هدف‌مون این بود که راجعبه چیزهایی صحبت کنیم که باعث میشن یک قدم خوانایی‌ کدمون بالاتر بره. در این قسمت از پایتونیک سراغِ یک مبحث خیلی پایه‌ای رفتیم که در عین سادگی‌ِ میتونه باعث افزایشِ خوانایی کد‌مون بشه. چند وقت پیش مطلبی جالبی رو خوندم که تو دلِ اون مطلب یکم راجعبه برابری و هویت متغییرها در پایتون بحث شده بود. دوست داشتم اون مطلب رو با شما هم به اشتراک بذارم. انتظار داریم در انتهای این قسمت به این نتیجه برسیم که درست‌ترین حالتِ استفاده از عملگر == و is به چه صورت هست و این اصل رو به صورت روزمره بکار ببریم.برابری Equalityتوی پایتون وقتی می‌خواهیم ببینم دو آبجکت با هم برابر هستند یا خیر، از عملگرهای == و =! استفاده می‌کنیم.هویت Identityدر مقابل‌ این عملگرها، دوتا عملگر دیگه هم داریم که is و is not هستند. is بررسی می‌کنه که آیا این آبجکت دقیقا یک آبجکت هستند یا نه. دقت کنید، ما داریم راجعبه چیزی فراتر از برابری حرف می‌زنیم. وقتی می‌گیم یکی هستند یا نه به صورت خیلی تخصصی یعنی اون دو متغییر دقیقاً در یک مکان از حافظه قرار گرفتند (ارجاعی به یک خونه از حافظه هستند)، یعنی این دو متغییر صرفا دو تا اسم هستند که دارند به یک جا اشاره می‌کنند.بریم با یک مثال مطلب رو بهتر جا بندازیم. توی قطعه کد پایین، با استفاده از تابع سازنده لیست، دو لیست مجزا (و خالی) رو در دو متغییر x و y ذخیره کردیم. دو متغییر x و z دقیقا به ایک آبجکت اشاره می‌کنند.چطور می‌تونیم بفهمیم دقیقاً به یک آبجکت اشاره می‌کنند؟ کافیه چک کنیم که هر متغییر دقیقاً به چه آدرسی از حافظه داره اشاره می‌کنه:و اگر از عملگر is بپرسیم که کدوم دو متغییر هویت یکسانی دارند:با توضیحات بالا شما باید الان یک همچین تصوری از این سه متغییر داشته باشید:همون‌طور که گفتیم، محتوای هر سه متغییرها یک لیست خالی هست، در نتیجه بدیهی که انتظار داشته باشیم خروجی عملگر == برای سه متغییر یکی باشه:نکته اول، در مواقعی که دو متغییر به یک آبجکت اشاره کنند، عملگر == خروجی is رو برای ما بر می‌گردونه.نکته دوم، این هست که هر آبجکتی می‌تونه نحوه بررسی == رو خودش پیاده‌سازی کنه. این کار توسط تابع‌ __eq__ (بخونید داندِر equal) انجام میشه. مثلاً می‌تونیم آبجکتی بسازیم که با هر چیزی مقایسه بشه، همیشه True برگردونه.اما برخلاف عملگر ==، هیچ روشی برای تغییر رفتار عملگر is وجود نداره! یعنی هیچ‌وقت عملگر is نمی‌تونه به ما دروغ بگه! همیشه به ما میگه که دو آبجکتی که دارن مقایسه می‌شن هویت‌شون (یک‌آدرس در حافظه) یکی هست یا نه.دقیقا کی باید از is استفاده کرد؟وقتی ابجکت‌هایی که در حال مقایسه هستند یکی از حالت‌های زیر باشند، به جای عملگر == باید از عملگر is استفاده کرد:True (Example: if sunny_day is True)False (Example: if normalize is False)None (Example: if username is None)چرا؟؟؟!چون این آبجکت‌ها به صورت پیش‌فرض توی پایتون به صورت singleton پیاده‌سازی شده‌اند. یعنی مهم نیست چند تا از این‌ها داشته باشیم. همه‌ی اون‌ها به یک آدرس از حافظه اشاره می‌کند.what does &#039;is&#039; operator do?خیلی از چیزهای دیگه با هم برابر هستند اما به هیچ‌عنوان به یک آدرس از حافظه اشاره نمی‌کنند. پس فقط برای سه حالت بالا از عملگر is استفاده کنید.Bad practiceجمع‌بندیبه طور کلی میشه گفت هر موقع به دنبال بررسی یکی بودن محتوای دو آبجکت هستیم، عملگری که باید استفاده بشه == هست. در مقابل، هر موقع انتظار میره که دو آبجکت هویتِ یکسان داشته باشند (به یک آدرس از حافظه اشاره کنند، یا دقیقا یکی هستند دو متغییر که صرفا به یک آدرس از حافظه اشاره می‌کنند) از عملگر is باید استفاده بشه.x is something_unique_objectاز اینجا کجا بریم؟بهترین کار درست‌ کردن کد‌های قدیمی هست. هر کجا چیزی شبیه کدهای پایین دارید رو به حالت درستش بازنویسی کنید:Bad patterns that should be fixed.اگر مطلب به صورت کامل برای شما جا نیفتاده می‌تونید لینک‌های پایین رو بررسی کنید:https://dbader.org/blog/difference-between-is-and-equals-in-pythonhttps://hackernoon.com/demysti-py-vs-is-dbf51d76df08</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Sat, 06 Apr 2019 11:51:02 +0430</pubDate>
            </item>
                    <item>
                <title>یک‌بار برای همیشه - ‌Comprehension‌ها</title>
                <link>https://virgool.io/@GreatBahram/once-for-all-comprehensions-mowjtailaa2s</link>
                <description>مقدمهسلام، امیدوارم که مثل همیشه خوش و خرم باشید. این‌بار می‌خوایم بریم سراغ یکی از ویژگی‌های خیلی خوب پایتون که شاید خیلی بهش‌ توجه نشده باشه. از طرفی دیگه ممکن هست که دید خوبی به این ویژگی‌ نداشته باشید. توی این قسمت از یک‌بار برای همیشه تصمیم گرفتیم یک بررسی کوتاه اما جامع روی comprehensionها توی پایتون داشته باشیم. یک نکته‌ای که دوست دارم توی ذهن‌تون ماندگار بشه این هست که comprehensionها ابزاری برای کم کردن تعداد خط‌های کد نیستند!دوباره، ‌comprehensionها ابزاری برای کم کردن تعداد خط‌های کد نیستند!!!معرفیمثل همیشه اولین گام یکی کردن ادبیات‌مون هست:اصطلاح اول iterable: توی قسمت iteratorها این مفهوم رو به صورت مفصل توضیح دادیم. هر چیزی  که به وسیله‌ی for loop هر بار یک آیتم از اون data type بگیریم iterable هست. مثل list، فایل‌ها، set و ... .اصطلاح list comprehension: به ما امکان ساخت یک لیست رو از یک داده‌ی iterable میده.اصطلاح generator: توی قسمت iteratorها این مفهوم رو به صورت مفصل توضیح دادیم پس اگر حس می‌کنید با این مطلب آشنا نیستید توصیه می‌کنم اول این قسمت رو یک مطالعه مختصر کنید. یک iterable تنبل رو generator می‌گیم.اصطلاح generator expression: با کمک این مفهوم ما یک generator می‌سازیم.اگر هر کدوم از این اصطلاحات کامل براتون جا نیفتاده، نگران نباشیم جلوتر همه رو به صورت عملی می‌بینیم!در پایتون هر متغییر در حقیقت یک ارجاع(رفرنس) به یک آبجکت‌ هست. در نتیجه توی حالت زیر وقتی سعی می‌کنیم که از لیست‌ای که داریم یک دونه کپی کنیم، هیچ کپی کامل‌ای رخ نمیده فقط دو اشاره‌گر به یک آبجکت به ما میده.list copy problemاگر تازه وارد پایتون شده باشید ممکنِ این رفتار یکم واسه شما عجیب بنظر برسه. به همین خاطر ساختن یک لیست از روی لیست دیگه توی پایتون خیلی کارِ رایجی هست. در حقیقت میشه گفت دلیل فلسفی وجودlist comprehensionها بهمین دلیل هست!توی مثال زیر ما یک لیست داریم و هدف‌مون محاسبه مجذور اعداد زوج هست:traditional wayهمین کار رو اگر بخوایم با لیست comprehension انجام بدیم این شکلی میشه:list comprehensionهمان‌طور که می‌بینید توی مثال بالا خیلی از اطلاعات به صورت فشرده توی یک خط نوشته شده، برنامه اول چهار خط کد داشت ولی اینجا همه‌چیز با یک خط انجام شده، اما بریم یکم بیشتر این ساختار رو بررسی کنیم. من سعی کردم با رنگی کردن هر بخش، بخش متناظر با اون رو توی لیست comprehension نشون بدم( اگر ابزار خوبی برای این کار رو می‌شناسید ممنون میشم به منم معرفی کنید):پس تقریباً ما می‌تونیم خیلی از for-loopها رو به راحتی تبدیل کنیم به list comprehension فقط کافیه ساختار بالا توی ذهن ما باشه. توی گیفِ پایین این‌‌کار به صورت عملی نشون داده شده:Copied from https://treyhunner.com  آیا واقعا لیست comprehension خوانایی کد رو کم می‌کنه؟به نظر من که خیر، چون وقتی توی پایتون شما یک قطعه کدی رو داخل ()، ‌[] یا {} بذارید، شما می‌تونید به هر حالتی که دوست دارید فاصله یا newline به کدتون اضافه کنید و خوانایی کد رو بالا ببرید. این ویژگی به ما کمک می‌کنه تا بتونیم خوانایی کد رو در حالت comprehension تا حد خیلی خوبی افزایش بدیم.make it more readableپس هیچ‌وقت نیاز به استفاده از \ برای اضافه کردن newline نداریم، مثال پایین غلط هست، هیچ‌وقت اینجوری ننویسید!wrong way!پس تا اینجای کار باید متوجه شده باشید که comprehensionها برای کم کردن تعداد خط‌های برنامه نیستند! comprehensionها راه دومی برای انجام کار قبلی هستند که فقط کد ما رو گویاتر و خواناتر می‌کنه، توی comprehension انگیزه توسعه‌دهنده در رابطه با کارش‌ محسوس‌تر هست.لازم نیست همیشه یک شرط داخل comprehension ما باشه. شرط‌ها فقط به ما کمک می‌کنند که یک فیلتر توی روند اجرای comprehension ایجاد کنیم.ما می‌تونیم یک comprehension تو در تو هم داشته باشیم مثل مثال بالا که به صورت غلط از \ برای جدا کردن خطوط داخل comprehension استفاده کرده بود. مثال:better way!نکته، comprehension‌ها فقط محدود به لیست نیستند و ما set comprehension هم داریم که مشابه حالت لیست برای ساخت یک set جدید به کار میرن، مثال:set comprehensionما dictionary comprehension هم داریم که خیلی از حالت‌ set پر کاربرد‌تر هست، توی مثال پایین ما خواستیم جای key-value روی توی دیکشنری‌مون عوض کنیم:dictionary comprehensionما چیزی به اسم tuple comprehension نداریم، چون generatorها خیلی توی پایتون کاربردی هستند، ما می‌تونیم یک generator رو توسط comprehensionها بسازیم اما دیگه بهش generator compehension گفته نیمشه بلکه اون رو با اسم generator expression می‌شناسیم.اگر با generatorها آشنا باشید پس میدونید که generatorها یک‌بار مصرف هستند یعنی اگر یک‌بار روی اون‌ها iterate کنیم دیگه امکان نداره به ایتم‌های اون بتونیم دوباره دست‌پیدا کنیم این در حقیقت با تعریف generatorها برابر هست!همین ما رو به سمت این نکته سوق می‌ده که هر موقع دیدید دارید یک list comprehension ای می‌سازید که فقط یکبار از اون استفاده می‌کنید بجاش از generator expression استفاده کنید! چرا؟ چون فلسفه‌ی وجودی این دوست‌مون برای همین کار هست!اما چطور یه دونه از اونا بسازیم، مثال(توجه کنید که فقط [] به () تغییر کرده):Generator expressionفقط یکبار استفاده ممکن هست در ابتدا خیلی ملموس نباشه، هر موقع می‌گیم یکبار استفاده، یعنی اون متغییری که ساختیم هیچ‌جای دیگه غیر از اونجا به کار ما نمیاد، در نتیجه نیازی نیست جوری ساخته بشه انگاه می‌خواهیم چندبار از اون استفاده کنیم. مثال خیلی واقعی‌ترش به صورت پایین میشه که یک مثال رو توی سه مدل با هم بررسی کنیم:Generator expressionکی نباید از comprehensionها نباید استفاده کرد:هر موقع دارید یک comprehensionای می‌سازید که نه چیزی رو فیلتر می‌کنه نه operationای روی داده‌ها انجام میده، اونجا احتمالاً دارید به صورت غلط از comprehension استفاده می‌کنید، مثال:مثال غلط دیگه می‌تونه ساخت لیست جدید از روی لیست قدیمی با کمک comprehension باشه، چرا می‌گیم غلط هست (پایتونیک نیست) چون تابع سازنده list برای همین ساخته شده:جمع‌بندییادمون نره comprehension برای کم کردن خط‌های کد نیستند!هر موقع دیدید دارید یک list comprehension یک‌بار مصرف می‌سازید، حتماً ازgenerator expression استفاده کنید.با استفاده از newline و در نظر داشتن PEP8 تا جایی که میشه comprehension‌ها رو خواناتر کنیم.اگر دنبال مثال برای تمرین می‌گردید این وب سایت می‌تونه کمک خیلی خوبی به شما بکنه: لینک.در پایان اگر جای خیلی باحالی از comprehensionها استفاده کردید خیلی ممنون می شیم اونارو هم با ما به اشتراک بذارید. اگر از این مطلب‌ خوشتون اومده اون رو توی شبکه‌های اجتمالی با دو‌ستان و همکار‌ خودتون به اشتراک بذارید. تا قسمت بعدی، خدانگهدار!</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Sat, 26 Jan 2019 16:17:35 +0330</pubDate>
            </item>
                    <item>
                <title>فراتر از ال‌پیک - کاپس</title>
                <link>https://virgool.io/@GreatBahram/%D9%81%D8%B1%D8%A7%D8%AA%D8%B1-%D8%A7%D8%B2-%D8%A7%D9%84%D9%BE%DB%8C%DA%A9-%DA%A9%D8%A7%D9%BE%D8%B3-opceoqtsvwts</link>
                <description>مقدمهسلام، امیدوارم که حالتون مثل همیشه خوب باشه! توی مجموعه‌ی فراتر از ال‌پیک هدف‌مون بررسی تکنولوژی‌ها یا ساختارهای یک سرویس و برنامه‌ی یونیکسی از دید یک توسعه‌دهنده است و هر بار سعی می‌کنیم چیزهایی که ممکن هست درک شما رو از یک سیستم یونیکسی بالاتر ببره با هم بررسی کنیم.اما هدف امروز بررسی سیستم مدیریت پرینت یونیکس یا CUPS به صورت عمیق و بررسی یک سری ایده‌ها توی این زمینه هست.در سیستم‌عامل‌های یونیکسی (مثل لینوکس و macOS) کارهای مربوط به پرینت مثل مدیریت کارهای چاپ، مدیریت صف، اضافه و حذف کردن دستگاه‌های پرینتر توسط برنامه CUPS انجام میشه. این برنامه توسط شرکت اپل برای سیستم‌عامل‌های یونیکسی توسعه داده شده. وقتی یک کاربر یک صفحه رو پرینت می‌گیره اتفاقات زیر توی سیستم رخ میده:کار توسط Spooler یا زمان‌بند به یک سری برنامه به اسم filter تحویل داده میشه. فیلتر‌ها وظیفه‌ی تبدیلِ فرمت دریافت شده به یک فرمت قابل فهم توسط پرینترها رو بر عهده دارند. مثلاً وقتی یک عکس‌ رو پرینت می‌گیرید، این فیلترها عکس‌ رو به یک فایل PDF تبدیل می‌کنند.در مرحله بعدی، فایل تبدیل شده توسط فیلترها به یک برنامه‌ای به اسم Backend تحویل داده میشه. بک‌اندها پل ارتباطی ما با پرینترها هستند. بک‌اندها فایل‌ رو از فیلتر می‌گیرند و به سمت پرینتر مورد نظر می‌فرستند. کاپس خروجی این بک‌اند رو چک می‌کنه تا بفهمه که عملیات پرینت موفقیت آمیز بوده یا نه. منظور من از خروجی، exit-code هست.در اعماقهر پرینتر معمولاً یک فایل PPD همراه خودش داره، این فایل در حقیقت حکم درایور رو برای سیستم‌عامل ایفا می‌کنه. توی این فایل گفته میشه که پرینتر چه ویژگی‌هایی داره: مثلا چه سایز برگ‌هایی، پشت‌رو، رنگ‌های پرینتر و ... . همچنین توی این فایل مشخص می‌شه که چه فیلتر‌هایی باید برای این پرینتر به کار گرفته بشن.در حقیقت فیلتر ها بسته به نوع فایل، به کار می‌رن، میشه گفت یک فایل دیتابیس طوری وجود داره که توی اون مشخص شده هر فرمت از فایل با چه فیلتری پردازش بشه، این دیتابیس رو می‌تونین توی آدرس پایین پیدا کنید:پس روال کلی این‌جوری شد که وقتی کاربر پرینت می‌گیره، کاپس فایل PPD مربوط به پرینتر رو (مثلا) می‌خونه و متوجه می‌شه که پرینتر چه ویژگی‌هایی رو پشتیبانی می‌که و توی صفحه پرینت شما به صورت گرافیکی این امکان رو میده که ویژگی‌های مورد نظرتون رو انتخاب کنید. در مرحله دوم برحسب نوع فایل فیلتر مورد نظر روی اون اعمال میشه و نهایتا فایل به تحویل بک‌اند داده میشه.بک‌اندهابک‌اند‌ها انواع مختلفی دارند و که امکان پرینت از طریق USB، روی https  یا اینترفیس‌های مختلف دیگه رو به ما میدن. برای کنجکاوی می‌تونید سری به آدرس پایین بزنید:پرینتر مجازیمهم‌ترین مطلبی که باعث شد من این مطلب رو بنویسم این بخش‌ از کاپس بود. پرینتر مجازی، چیزی هست که دقیقاً مشابه یک پرینتر فیزیکی عمل می‌کنه یعنی وقتی Ctrl+p می‌زنید جزء پرینتر‌های شما نشون داده میشه اما واقعاً وجود فیزیکی نداره. مثلا وقتی با برنامه‌ی Micrsoft word دارید کار می‌کنید می‌تونید قبل از پرینت گرفتن یک Preview از پرینت داشته باشید.شما می‌تونید یک پرینتر مجازی برای کاپس تعریف کنید و بجای پرینت کردن، کار دیگه‌ای که مد نظر خودتون هست انجام بدید.فرض کنید، توی شرکت fax.ir هستید و قصد دارید کاری کنید که همه به جای خرید دستگاه فکس، فکس‌هاشون رو به شما بفرستند و شما کار فکس اونارو در ازای دریافت هزینه انجام بدید. این کار می‌تونه این‌شکلی باشه که شما یک دستگاه پرینتر مجازی داشته باشید که با اون کاربران به اشتراک بذارید و فایل‌ها به جای پرینت به مخزن شما ریخته بشن و شما اونارو با برنامه‌ی دیگه فکس کنید!ایده‌ی دیگه می‌تونه میل به جای پرینت باشه، مثلا هر بار که خواستید یک چیزی رو برای کسی بفرستید به جای باز کردن میل و پیوست کردن اون، فقط Ctrl+p بزنید و به صورت خودکار انجام بشه.برای این از قبیل کار‌ها میشه از پرینتر مجازی استفاده کرد. برنامه کاپس خیلی ماژولار نوشته شده و به راحتی می‌تونید هم فیلتر مورد نظر خودتون و هم بک‌اندی رو که دوست دارید بهش اضافه کنید.در ادامه چند پروژه که توی این مسیر به من کمک کردند و می‌تونن روشن کننده مسیر برای شما هم باشند با هم بررسی می‌کنیم.پروژه اول، اسمش Boomaga هست که کار اون این هست که قبل از پرینت گرفتن عکس یا هر چیزی امکان دیدن یک Preview از اون رو به شما میده.پروژه دوم، fax4cups هست که همون‌طور که از اسمش پیداست به شما امکان فکس کردن رو به جای پرینت کردن میده.پروژه سوم، pdf2email که بعد از کانفیگ اولیه این امکان رو به شما میده که هر فایلی که با این پرینتر مجازی پرینت می‌گیرد به میل‌ادرسی که بهش می‌دید فرستاده بشه.در نهایت من یک نمونه کد برای شروع روی گیت‌هابم گذاشتم که پایه‌ی کار رو نوشتم و می‌مونه اون چیزی که شما قصد پیاده‌سازی‌‌اش رو دارید.تا قسمت بعدی فراتر از ال‌پیک خدانگهدار!</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Mon, 24 Dec 2018 15:17:05 +0330</pubDate>
            </item>
                    <item>
                <title>یک‌بار برای همیشه - Parallelism 2</title>
                <link>https://virgool.io/@GreatBahram/once-for-ever-parallelism2-bsaucpjhzy6s</link>
                <description>سلام! توی این قسمت از یکبار برای همیشه ادامه‌ی قسمت قبلی در رابطه با موازی‌سازی در پایتون رو در پیش داریم. در یک‌بار برای همیشه  بحثی رو مطرح می‌کنیم که خیلی در نگاه اول شاید راحت بنظر نرسه، و این‌جا  سعی می‌کنیم با بیان ساده‌تر و مثال‌های خیلی خیلی ابتدایی اون مطلب رو به  راحتی به مخاطب انتقال بدیم.هدف اصلی ما توی این قسمت معرفی یکی از راه‌حل‌هایی هست که به کمک اون می‌تونیم به آقای GIL غلبه کنیم.مقدمهدر قسمت قبل در این رابطه صحبت کردیم که مفسر پایتون  thread-safe نیست در نتیجه امکان حداکثر بهره‌وری از منابع پردازشی سیستم توسط مالتی‌تردینگ برای ما میسر نیست. به این موضوع هم اشاره کردیم که این روند روی اجرای برنامه های I/O bound  خیلی تاثیری منفی نداره و تاثیر اون بیشتر در برنامه‌های CPU bound هست که اجازه کار با تمام هسته‌های پرازنده‌مون از ما گرفته شده است.اما خب برای مشکل فوق هم راه‌ حل‌های مختلفی معرفی شده که در این آموزش قصد بررسی یکی از این راه‌حل رو داریم. مساله اصلی این‌جا بود که ترد‌های مختلف برای اجرای کد‌های مربوط به خودش باید صبر کنند تا GIL را بدست بیارند (Acquire) و همین‌ مساله در عمل مساوی هست با اجرای یک ترد در هر لحظه از زمان. این مشکل در یک پردازنده چند هسته‌ای یعنی فقط یک هسته از هسته‌های پردازنده به کار گرفته میشه.راه حلِ Multiprocessingراه‌‌حلی که کمک می‌کنه تا بتونیم از دستان پر توانِ GIL فرار کنیم، استفاده از پراسس به جای ترد هست. پراسس چطور می‌تونه این مشکل رو حل کنه؟ توی این حالت در حقیقت هر پراسس یک مفسر پایتونِ جداگانه داره و از طرفی هر پراسس رو روی یک هسته از پردازنده اجرا میشه یعنی هر پراسس GIL مربوط به خودش رو داره. درنتیجه هیچ پراسسی منتظر گرفتن GIL نمی‌مونه و اینجوری تا حد خیلی زیادی می‌تونیم از منبع پردازشی سیستم به صورت خیلی موثر استفاده کنیم.در قسمت قبل گفتیم که مفسرِ پایتون در حالت single-thread به خاطر وجود GIL نسبت به زبان‌های برنامه‌نویسی دیگه خیلی کارآمد‌تر عمل می‌کنه و همین دلیل باعث میشه تا توی حالت مالتی‌پراسس هم تا حد زیادی از تمام منابع پردازشی‌ سیستم بهره ببریم.خوشبختانه توسعه‌دهنده‌های پایتون یک ماژول تر و تمیز برای این کار نوشتند که اسم اون ماژول multiprocessing هست و این ماژول بشدت شبیه threading هست. تو آموزش قبلی یک مثالِCPU bound داشتیم که حدوداً ۶ ثانیه اجرای اون طول می‌کشید و سعی کردیم با اضافه کردن ترد بهترش کنیم اما تاثیرِ مثبتی نداشت! کد اولیه‌مون این شکلی بود:استفاده از پراسس در پایتونبرای تعریف یک پراسس توی پایتون کافیه از کلاس Process از ماژولِ multiprocessing کمک بگیریم. همون‌طور که می‌بینید نحوه ساخت و متدهای اون بشدت شبیه ماژول threading هست. ساخت و کنترل پراسس برای ما تنبل‌ها کار سختیه، پس بریم سراغ یک راهِ حل ساده‌تر!استفاده از ProcessPoolپراسس‌پول، در واقع مجموعه‌ای از پراسس‌ها هستند که منتظر دریافت کار می‌مونند و جواب‌ها به ما بر می‌گردونند. توی مثال پایین ما یک پراسس‌پول ساختیم و کارمون رو به پراسس‌ها به کمک متدِ map وصل کردیم.از اون‌جایی که قرار هست از تمام هسته‌های پرازنده‌مون استفاده کنیم، اولین‌گام این هست که بفهمیم پردازنده‌ی ما چند‌هسته پردازشی داره. این کار رو می‌تونیم به کمک تابع cpu_count انجام بدیم.دقت کنیم وقتی یک instance از Pool می‌سازیم خودش به صورت پیش‌فرض تعداد پراسس‌ها رو به اندازه هسته‌های cpu می‌گیره (فقط به خاطر جنبه‌ی آموزشی داخل پرانتز تعداد پراسس‌ها رو مشخص کردیم).با کمک ماژولِ multiprocessing، این زمان اجرا برنامه ۵۰‌درصد کاهش داشته و توی ۳ ثانیه اجرا شده، نشون میده که دوست خوبی می‌تونه توی این مسیر برای ما باشه.تا این زمانی که من دارم این مطلب رو می‌نویسم، به کمک چهار روش(متد) میشه کار‌ها رو به یک ترد‌پول تقسیم کنیم. نکته دوم، این که تمام این متد‌ها به صورت پیش‌فرض باعث بلاک شدن ادامه‌ی اجرای برنامه میشن، یعنی بقیه کدهای پایین این متد‌ها اجرا نمیشه تا این‌ متد‌ها کارشون تموم بشه یا به عبارت دیگه  synchronously اجرا میشن. به همین خاطر تمام این متد‌ها همشون یک نسخه‌ی non-blocking هم دارند. برای این‌کار کافیه به انتهای اسم این متد‌ها async_ اضافه بشه تا به صورت asynchronously اجرا بشن به طور مثال map_async. نکته سوم، اکثر این متد‌ها فقط یک آرگومان برای ورودی تابع موردِ اجرا قبول می‌کنند که در حقیقت می‌تونیم یک لیست از tuple به عنوان ورودی بدیم تا داخل تابع‌ مورد نظرمون اون tuple رو unpack کنیم.متد map: این متد و بقیه دو‌ستانش که پایین‌تر راجعبه‌ اونا توضیح می‌دم، هدف‌شون این هست که مجموعه‌ای از کارهای‌ ورودی که iterable هستند رو به پراسس‌های مختلف وصل کنند. این متد ترتیب رو رعایت می‌کنه، به هر طریقی که ورودی رو بهش بدید همون‌طور هم خروجی رو به شما تحویل میده. برای درک بیشتر مثال زیر را بررسی کنید.خروجی:متد imap: تنها تفاوت‌ متدِ imap با متد map اینِ که imap هر جوابی که آماده بشه رو به شما میده، منتظر تمام شدنِ کل کارها نمی‌مونه. در حقیقت میشه گفت حرف iای ابتدای map علامت iterator بودن اون هست. پس هر موقع نیاز دارید هر result ای که آماده شده سریع بهش دسترسی داشته باشید و ترتیب هم برای شما اهمیت داده imap دوست خوب شماست. مثال:خروجی‌اش با مثال قبلی هیچ‌ تفاوتی نداره مهم memory efficient بودنش هست.متد imap_unordered: کاملاً مشابه imap فقط ترتیب کار‌ها دیگه اینجا اهمیت نداره! برای کارهای مستقل از هم مناسب هست. مثال:خروجی:متد startmap: این متد فقط یک تفاوت با متد map داره، اون این هست که ورودی‌های تابع موردِ اجرا رو برای ما unpack می‌کنه در نتیجه دیگه نیازی نیست این کار رو خودمون انجام بدیم.ماژول concurrent.futures هم یک پراسس‌پول در اختیار ما می‌ذاره اما چون رابط کاربری اون و هم‌چنین کارایی اون ساده‌تر و کندتر از ماژول multiproessing بود، ترجیح من معرفی یکی از این دو تا ماژول بود.جمع‌بندی به طور کلی میشه گفت مزیت اصلی این روش دور زدن GIL و به کارگیری تمام منابع پردازشی سیستم هست. اما خب حتما این روش هم معایبی داره! بزرگترین عیبی که میشه به این روش گرفت نبود یک حافظه مشترک بین پراسس‌ها هست (Shared memory). توی قسمت قبل، پراسس با چندین ترد داشتیم، که همه در یک حافظه مشترک (توی پراسس اصلی) فعالیت می‌کردند. تصویر یک پراسس با چندین ترد با حافظه مشترک:Image is from https://www.toptal.comاما وقتی وارد دنیای مالتی‌پراسس می‌شیم، فضا کاملاً متفاوت میشه، این‌جا پایتون باید برای هر پراسس یک کپی از فضای حافظه پراسس اصلی بسازه، تا این پراسس‌ جدید بتونه فعالیت مورد نظر ما رو پردازش کنه، تصویر نحوه کارِ مالتی‌پراسس:Image is from https://www.toptal.comارتباط بین پراسس‌ها یا همون inter-process communication هم با استفاده از ماژولِ multiprocessing امکان‌پذیر هست که این توسط multiprocessing.Queue انجام میشه.پس به طور کلی معایب این کار عبارتند از:هزینه بالای ارتباط به پرداسس‌هاعیب‌ دوم که در حقیقت دنباله‌ی همون عیب اول هست، مصرف زیاد حافظه اصلیِ ( راه حل‌هایی هم هست لینک).مشکل دیگه‌ای که شاید بشه به multiprocessing گرفت، scalable نبودنش هست که ما رو مجبور می‌کنه به سمت چیزایی مثل Celery بریم. به عنوان جمع‌بندی بهترِ گفت که هر مساله‌ای راه‌حل خودش رو داره و ماژول multiprocessing توی خیلی از مواقع راه‌حل کم‌هزینه و مناسبی هست.این بود پایان این قسمت از یک‌بار برای همیشه! اگر از این قسمت‌ خوشتون اومده نظر خودتون رو در پایین با ما به اشتراک بذارید و این قسمت رو با دوستانِ پایتونی خودتون در شبکه‌های اجتماعی به اشتراک بذارید!از این‌جا کجا برممطالعه بیشترhttps://blog.sopticek.net/2017/06/03/concurrent-and-parallel-programming-in-python-part-2/https://medium.com/apteo/multi-processing-in-python-ee0ce73a459bhttps://docs.python.org/3/library/multiprocessing.htmlکدهای استفاده شدهhttps://github.com/GreatBahram/OnceForEver/tree/master/code_snippets/parallelism/part2-multiprocessing</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Sat, 01 Dec 2018 18:52:03 +0330</pubDate>
            </item>
                    <item>
                <title>یک‌بار برای همیشه - Parallelism 1</title>
                <link>https://virgool.io/@GreatBahram/once-for-ever-parallelism-1-iqyzjwqmks0n</link>
                <description>سلام به همه دوستانِ پایتونی! توی این قسمت از یکبار برای همیشه سراغِ مبحثِ پیچیده‌تری به اسم Parallelism رفتیم. در یک‌بار برای همیشه بحثی رو مطرح می‌کنیم که خیلی در نگاه اول شاید راحت بنظر نرسه، و این‌جا سعی می‌کنیم با بیان ساده‌تر و مثال‌های خیلی خیلی ابتدایی اون مطلب رو به راحتی به مخاطب انتقال بدیم. هدف اصلی ما، معرفی چالش‌های موجود در پایتون در بخش Parallelism و همچنین معرفی راه‌حل‌هایی برای غلبه بر اون چالش‌هاست. اما خب مثل همیشه رسیدن به اون نقطه پیش‌نیازش تعریف خیلی دیگه‌ از چیز‌ها هست. هدف این آموزش استفاده از ترد یا پراسس نیست و فقط یک معرفی ساده و مختصر در رابطه با اون‌ها داریم. در این آموزش‌ نه اینقدر عمیق می‌شیم که فکر کنیم کلاس درسِ دانشگاه‌اس نه اینقدر سطحی می‌ریم جلو که نفهمیم چی‌ به چی هست!مقدمههمه‌ی ما می‌دونیم که پایتون یک زبان مفسری  (Interpreted language) هست، یعنی وقتی برنامه داره اجرا می‌شه شبیهِ این هست که یک آدم کد رو از بالا می‌خونه به هر خط کد که می‌رسه اون خط رو اجرا می‌کنه . اما اجرای برنامه‌ها به صورت موازی یا Parallelism یکم تفاوت ایجاد می‌کنه. اول از همه بریم با تعریف این مفهوم آشنا بشیم:مفهوم Parallelism به چه معناست؟این مفهوم به ما این فرصت رو میده که یک کار بزرگ رو به چند بخش تقسیم کنیم و بتونیم با این تکنیک سرعت اجرای برنامه‌مون رو بالا ببریم. نکته‌ای که باید مدنظر باشه این هست که ما باید یک‌کار داشته باشیم که قابلیت اجرا به صورت موازی رو داشته باشه و ثانیاً منابع‌ای رو هم که برای اجرا نیاز داره رو هم در اختیار داشته باشیم و اون موقع میشه گفت که ما داریم کار‌ها به صورت همزمان(موازی) اجرا می‌کنیم.مثل همیشه تصویر این کارممکن درک موضوع رو راحت‌تر کنه، حالت اول یک کار داریم و کار مورد نظر توسط چیزی (ترد یا پراسس) در حالِ اجرا شدن هست:Old days in computer world!حالت دوم همون کار رو که قابلیت موازی سازی داشته و همین‌طور با کمک منابع مورد نیازش به صورت موازی  اجرا میشه:Parallelismاصولاً ابزارهایی از جنس سیستم‌عامل که به ما در موازی اجرا کردن برنامه‌ها کمک می‌کنند پراسس‌ها و ترد‌ها هستند.پراسس یا Processبه هر برنامه‌ای که در حال اجرا باشه توی دنیایی کامپیوتر Process گفته می‌شه. هر Process یک سری اطلاعات راجعبه خودش نگه می‌داره که چیزی شبیه شناسامه‌ی اون هست به این بخش (Process Control Block) یا PCB گفته میشه و هر Process یک شناسه‌ی یکتا داره که به اون PID گفته میشه که اون رو داخل همین شناسامه با اطلاعات دیگه‌ نگه داری می‌کنه.دوست خوب ما Thread به کوچکترین بخشی از یک Process که به صورت کاملاً مستقل میتونه توسط سیستم عامل اجرا بشه، Thread گفته میشه. Threadها می‌تونن وضعیت‌های مختلفی داشته باشند:در حال اجرا باشند(running)آماده اجرا (ready)صبر کردن (waiting)کار رو به انجام (done) رسونده باشند هر Thread هم یک شماره داره که سیستم عامل با اون شماره‌ها اینارو کنترل می‌کنه که بهشTID یا (Thread IDentifier) گفته میشه. هر Thread میدونه فرزند کدوم پروسس بوده این کار رو توسط یه اشاره گر به پدرش به خاطر می‌سپاره که اصطلاحا بهش (Parent Process Pointer) گفته میشه.مهم‌ترین نکته: هر Process می‌تونه چندین Thread داشته باشه، که همه‌ی این تردها می‌تونن به منابعی که پروسس دسترسی داره دسترسی داشته باشن و یک حافظه مشترک داشته باشند. مهمترین مزیتی که باعث میشه ما از ترد‌ها خوشمون بیاد این حافظه مشترک‌شون هست که دسترسی به این حافظه مشترک خیلی هزینه کمی داره و بدترین چیزیم که ترد‌ها دارن همین حافظه مشترک هست چون مشترک هست ممکنِ توی مدیریت‌اش به مشکل بخوریم و خراب‌کاری زیادی به بار بیاد که به این وضعیت race condition  گفته میشه.پس میشه به نوعی گفت که پراسس‌ها به‌ نظر شبیه یک محیطی برای نگهداری ترد‌ها هستند (Container).از طرفی میشه برنامه‌های که توسط کامپیوترها اجرا میشن رو به دو دسته تقسیم‌بندی کرد:CPU boundI/O boundتفاوت بین برنامه‌های CPU bound و  I/O bound؟برنامه‌ای CPU bound هست که اگر ما پردازنده‌ی قوی‌تری داشته‌ باشیم اون برنامه سریع‌تر اجرا بشه، به عبارت دیگه برنامه‌ی ما بیشتر وقت‌اش رو با پردازنده درگیر هست. از طرفِ دیگه برنامه‌ای I/O bound هست که اگر ما منابع I/O مثلِ هارد دیسک، کارت‌های شبکه قوی‌تر و سریع‌تری داشتیم اون برنامه خیلی سریع‌تر اجرا می‌شد. پس فقط کافیِ نگاه کنیم با اضافه کردن کدوم یکی از منابع‌ سرعت اجرای برنامه بیشتر میشه. داستانِ MultiTaskingوقتی کامپیوتر‌ها تازه اختراع شده‌ بودند، هر CPU فقط امکان اجرای یک پروسس رو داشت. یعنی شما اگه داشتید با Word کار می‌کردید دیگه نمی‌تونستید alt-tab بزنید برید روی پروسس دیگه. در نتیجه تنها راهی که داشتید بستنِ برنامه اول و باز کردن برنامه دوم بود. این عیب باعث شد چیزی به اسم context switching به سیستم عامل اضافه بشه. این دوست عزیزمون این اجازه رو به ما میده که بتونیم وضعیت فعلی پروسس‌رو یه جایی ذخیره کنیم و سوئیچ کنیم روی یک برنامه‌ی دیگه و اگه خواستیم برگردیم ادامه کارمون رو بدیم، سیستم عامل وضعیت اون برنامه رو می‌خوند و ادامه‌ی داستان. این سوئیچ‌ها وقتی رخ میده که یک وقفه رخ بده (معروف به Interrupt). نکته‌ی اصلی‌تر اینِ که سیستم عامل اینقدر سریع این‌کارو انجام میده که کاربر فکر می‌کنه در هر لحظه تمام پروسس‌ها در حال اجرا هستند. درنتیجه به یک مفهوم زیبایی به اسم multitasking داریم می‌رسیم.داستان به اینجا ختم نشد؛ با گذشت زمان بازم با مشکل مواجهه شدیم اما این‌بار در ابعاد کوچک‌تر. فرض کنید قصد داریم یک بخش از داکیومنت‌ی رو چاپ کنیم تنها راه‌حل باز کردن یک پروسس دیگه بود که خیلی هزینه‌بر هست، این مساله باعث ورودِ مفهوم ترد به دنیای کامپیوتر شد. پس میشه گفت که هر ترد یک پروسس خیلی خیلی سبک شده‌است. ساخت و استفاده از تر‌دها از نظر هزینه محاسباتی خیلی خیلی به صرفه‌تر از پروسس به صورت پیش فرض هست.نکته: یادمون باشه، روی یک پردازنده تک‌هسته‌ای هم می‌تونیم multitasking داشته باشیم فقط کافی هست یک کسی باشه که این سوئیچ‌ها رو مدیریت کنه!اکثر برنامه‌های امروزی معمولا از چند تا ترد استفاده می‌کنند. مثلا برنامه‌ی gedit اگر باز کنید، می‌بینید که حداقل از سه‌ تردِ فعال داره: جمع‌بندی تا اینجای کارتا الان یادگرفتیم سیر تاریخی دنیای کامپیوتر چی بوده، که خیلی خلاصه‌اش این بوه که ما همیشه به دنبال بهره‌بردن بیشتر از منابع‌مون بودیم و این کار روش‌های مختلفی رو طلبیده تا به ترد رسیدیم. و همین‌طور گفتیم که ترد‌ها در حقیقت بخشی از پراسس‌ محسوب می‌شن و کمک می‌کنن که خیلی بهتر از منابع‌مون استفاده کنیم. اما بنظرم دیگه داستان و تاریخ کافیه بریم سراغ اینکه چطور می‌تونیم با ترد‌ها توی پایتون کار کنیم.ترد‌ در پایتونیکی از پادکست‌های خیلی خوب در رابطه با پایتون، پادکستِ Talk Python to me هست که واقعاً بنظرم خیلی باحال هم هست. خب چی‌میشه شمایی که مثلاً الان باهاش آشنا شدی دوست داشته باشید تمام قسمت‌های اون رو دانلود کنید؟ این برنامه اگر با یک ترد اجرا بشه بهتره یا چندتا؟ آیا طبق افسانه‌ها استفاده از ترد در پایتون هیچ سودی نداره؟خب توی این بخش یک برنامه‌ی خیلی ساده نوشتیم که اول از همه لینک همه قسمت‌ها رو از وب سایت پادکست بدست میاره و بعد هر لینک رو جداگانه باز می‌کنه تا آدرس فایل صوتی پادکست از اون آدرس استخراج کنه و نهایتاً همه‌ لینک‌ همه‌ی قسمت‌های پادکست رو به ما برمی‌گردونه. برای ساده‌سازی ما دیگه از بخش دانلودش می‌گذریم ( به کد برنامه از اینجا می‌تونید دسترسی داشته باشید). برنامه به این صورت هست:همون‌طور که می‌بینید دو تا تابع اصلی داریم: تابع get_episodes_link که در حقیقت کاری لینک تمام ایپزود‌های پادکست رو بدست بدست میاره.تابع دوم، تابع get_audio_link هست، که به عنوان ورودی یکی از لینک‌های بالا رو می‌گیره و آدرس فایل صوتی اون قسمت رو به ما میده.مشخصات کامپیوتری که در این قسمت استفاده شده:اجرای این برنامه به صورت عادی (یعنی با یک پراسس و یک ترد اصلی) تقریباً 120 تا 160 ثانیه طول زمان می‌بره تا اجرا بشه.اولین ناجیاما حالا که با مفهوم ترد آشنا هستیم، بریم اولین قدم رو برداریم تا سرعت برنامه‌مون رو بهبود بدیم. اول از همه برای دوستانی که آشنا نیستند، برای کار با ترد در پایتون یک ماژول سطح بالا داریم به اسم threading که امکاناتِ خیلی خوبی به ما میده، یکی از ابتدایی‌ترینِ این امکانات ساخت ساده‌ی ترد هست، مثال (لینک):نکته‌ی اول اینکه، اگر در برنامه بالا از ترد استفاده نمی‌کردیم وقتی برنامه‌مون رو به صورت عادی اجرا می‌کردیم برنامه موقع‌‌ی اجرای تابع long_function تا ۵ ثانیه متوقف می‌شد بعدش ادامه‌ی برنامه‌ اجرا می‌شد.اما الان برنامه‌ی ما دو تا ترد داره. یکی ترد اصلی که کل برنامه‌ رو اجرا می‌کنه و دیگری تردِ جدیدی که ساختیم و در نتیجه برنامه ما به هیچ‌عنوان بلاک نمیشه یعنی تابع‌ی long_function توسط یک ترد جداگانه در حال اجرا هست. نحوه ساخت‌اش رو همون‌طور که می‌بینید خیلی راحت هست. بعد از این‌که با مشخص کردید چه کاری(از طریق target) و چه ورودی ( از طریق args و kwargs) رو باید بگیره. با متد start می‌تونید به ترد بگید که اجرا بشه.بعضی اوقات شما ممکنِ نخواهید ادامه کار رو انجام بدید مگر اینکه ترد‌ها به پایان رسید باشند. اینجا متد join به شما کمک می‌کنه و برنامه متوقف می‌شه تا ترد‌ها کارشون تموم بشه.اما بریم توی برنامه‌ی خودمون با استفاده از ترد سعی کنیم کاری بکنیم که برنامه‌ سریع‌تر از قبل اجرا بشه ( برای اینکه کد‌ها توی یک عکس جا بشن، بخش‌های که هیچ تغییری نکردن رو من دیگه اینجا نشون ندادم! لینک) : گفتیم اولین قدم توی موازی سازی، اینِ هست که برنامه‌ی ما قابلیت اجرا به صورت موازی رو داشته باشه (تا حدی مستقل از هم باشند). برای اینکه برنامه ما موازی اجرا بشه تعداد ترد‌ها رو یک عدد خاص در نظر گرفتیم که توی متغییرِ num_of_threads ذخیره میشه.در قدم دوم باید کار‌ها ( لینک‌ها) رو بین اونا تقسیم کنیم. توی این زمانی که من دارم این مقاله آموزشی رو می‌نویسم ۱۸۵ قسمت از این پادکست منتشر شده، در نتیجه نیاز داریم تا این لینک‌ها رو بین ترد‌ها تقسیم کنیم، که این تقسیم کردن توسط حلقه forای که می‌بینیم انجام می‌شه.در نهایت این لینک‌ها به تابع جدیدِ get_bunch_audio_links داده شدند و هر ترد مسئول اجرای این تابع است. بنظر شما آیا اضافه کردن ترد‌ تاثیری توی کاهش زمان اجرای برنامه داره؟توی جدول پایین من تعداد ترد‌ها و میزان زمانی که صرف شده رو گذاشتم(لینک):با شروع کار تقریبا زمان رو به نصف زمان قبلی کاهش دادیم(هر بار برنامه برای اطمینان بیشتر دوبار اجرا شده است). در ادامه وقتی دیدیم که ترد‌ها چقدر خوب دارن کار می‌کنن سعی کردیم تعداد رو هی بیشتر کنیم تا  زمان اجرا در مقابلش کمتر بشه. اما این کار تا یک جایی ادامه داشته و از یک نقطه‌ای به بعد دیگه میشه‌ گفت هیچ‌ تاثیرِ مثبتی! نداشته و ما رو به قانون امدال رسونده.تحلیل بیشترمهم‌ترین نکته این هست که تشخیص بدیم برنامه‌ی ما بیشتر با پردازنده سروکار داره یا یا منابع I/O؟ مثال بالا دیتایی رو از وب دریافت می‌کرد و لینکی مورد نظر رو از اون دیتا بدست می‌آورد. طبق تعریفی که در بخش اول داشتیم پس این کار قطعاً IO bound هست. ممکنِ تا اینجای کار بعضی‌ از خواننده با خودشون فکر کنند که چرا برخلاف باوری که میگن پایتون برای مالتی‌تردینگ خوب نیست نتایجِ بدست اومده چیزی دیگه‌ای میگن؟؟ دلیل اصلی اینِ که ما یک کار IO bound رو داشتیم اجرا می‌کردیم. (خب بازم این که نشد جواب؟) هنوز چرای ما پابرجاست.نکته‌ی دوم که شاید خیلی بهش دقت نشه، اضافه کردن بیش از اندازه ترد‌ها بود و چون ما خیلی یک برنامه‌ی خاص منظوره‌ برای نشون دادن منظورمون رو داشتیم متوجه‌ی بد‌ی‌های این کار نشدیم. تعداد زیاد ترد مساوی هست با مصرف زیاد حافظه  و هم‌چنین زیاد کردن context switching.با کمک دستور time منابع مصرف شده رو وقتی که با ۵ تا ترد برنامه‌مون رو اجرا کردیم:در مقابل وقتی که ۱۰۰تا ترد استفاده شده:مفهوم ThreadPoolقبل از اینکه بریم سراغ مباحث پیچیده‌تر به یک نکته‌ای در رابطه با ترد‌ها توی پایتون اشاره کنم. معمولا انتظار نمی‌ره شما به صورت مستقیم برای کار‌های روزمره‌تون از threading استفاده کنید. چرا؟ فرض کنید چهار‌تا ترد نیاز دارید. اولاً، شما باید چهار ترد بسازید. ثانیاً، کار مورد نظر رو باید بهشون بدید و ترد‌ها رو اجرا کنید. نهایتاً، بررسی کنید که کامل اجرا شدند یا خیر؟ راه حل بهتر هم وجود داره!مفهوم به اسم ThreadPool؟ تردپول که در حقیقت مجموعه‌ای از تردها است که همیشه منتظر ورودی برای پردازش هستند و کار کردن با اون‌ها به مراتب تمیزتر و ساده‌تر از روشی‌ هست که بالا انجام دادیم.این چیز خیلی باحال توی ماژول concurrent قرار داده، کد جدیدمون این میشه (لینک):بنظر من که حسابی خوشگل‌تر شده ;-) دیگه نه نیاز به یک تابع اضافی مثل get_bunch_audio_links بوده و نه کارها (لینک‌ها) رو تقسیم کردیم. معرفی گیلبررسی موضوع از زاویه دیگر!وقتی شما یک برنامه پایتون‌ رو اجرا می‌کنید، یک پراسس پایتون اجرا میشه که روی یک هسته از پردازنده اجرا میشه. این پراسس به صورت پیش‌فرض یک ترد داره و همین‌طور گفتیم که امکان ساخت ترد‌های بیشتر هم وجود داره. اما این‌کار چه مزیتی برای ما داره؟ چه تفاوتی بین یک کامپیوتر با پردازنده تک هسته‌ای و وقتی که چندین هسته داره وجود داره؟ در کامپیوتر تک هسته‌ای وقتی چندین ترد بسازیم معادل این هست که به کامپیوتر بگیم بین ترد‌های مختلف سوئیچ کن. اما وقتی یک پردازنده‌ی چند هسته‌ای داریم، اون موقع چی؟ آیا بازم هدفمون این هست که تردهای جدید روی همون هسته‌ای اجرا بشن که ترد اصلی هست یا هدف این هست که از هسته‌های دیگه‌ هم استفاده کنیم؟بدلیل نحوه‌ی پیاده‌سازی پایتون، شما نمی‌تونید دو یا چندتا ترد از یک پراسس رو به صورت همزمان روی چند هسته از پردازنده‌تون در حال اجرا داشته باشید! چرا؟ چون هر پراسس از پایتون یک منبع خاصی رو می‌سازه که هر ترد برای اجرا به اون منبع خاص احتیاج داره. اما اون منبع (به دلیل اینکه) فقط یه دونه‌اس در نتیجه ما چند ترد از یک پراسس رو نمی‌تونیم به صورت همزمان در حال اجرا داشته باشیم. اسم اون منبع GIL (Global Interpreter Lock) هست. یک اصطلاحی معرفی هست به اسم Thread-safe و به پیاده‌سازی گفته میشه که موقع اجرای چندین تردِ همزمان باعث جلوی ناسازگاری یا race condition رو به طریقی بگیره. برای رسیدن به یک وضعیت Thread-safe توی پایتون ما نیاز به استفاده از مفهوم لاک Lock رو داشتیم که اسم این لاک رو GIL گذاشتیم. یا به عبارت دیگه چون روشِ memory management‌ سی‌پایتون thread-safe نیست برای رسیدن به این وضعیت از Lock استفاده شده .ممکن است یک خواننده‌ای بپرسه ترد رو که اصلا سیستم عامل مدیریت می‌کنه حرف شما اصلاً منطقی نیست. درستِ ترد رو سیستم عامل مدیریت می‌کنه اما وقتی ترد نیاز به داده‌ای داره که در اختیار پایتون هست و پایتون مدیریت‌حافظه‌اش thread-safe نیست باید صبر کنه تا رو بدست بگیره (acquire) و این یعنی فقط یک ترد در حال اجرا داشته باشیم.در اعماقِ گیلروشی که برای مدیریت حافظه در پایتون استفاد شده reference counting اسمش هست. که به این معنی هست که به ازای هر آبجکت داخل پایتون، یک reference count داریم که تعداد ارجاع‌ها به این آبجکت رو نگه‌ می‌داره. هر موقع هم این مقدار صفر بشه، یعنی بخشی از حافظه که توسط این آبجکت اشغال شده آزاد شده.مثال:مشکل از این‌جا شروع میشه که اگر چند ترد همزمان به این ‌reference countها دسترسی داشته باشند، این مقدارها افزایش یا کاهش غیر‌انتظاری، به خاطر ذات موازی‌سازی، پیدا می‌کنند. راه حل این‌ بوده که یا از چندین Lock برای هر آبجکت استفاده کنیم یا این‌که یک Lock سراسری داشته باشیمو با انتخاب یک Lock سراسری هر بایت‌کد که بخواد اجرا بشه باید بتونه این Lockرو در دست بگیره.یک مثال CPU boundبرنامه ساده پایین رو وقتی به صورت معمولی( یک ترد اصلی) اجرا می‌کنیم(لینک):چیزی حدود ۶ ثانیه زمان می‌بره تا اجرا بشه. برای سریع‌تر شدنش می‌ریم که یک ترد دیگه به برنامه‌مون اضافه کنیم و کار رو بین این دوتا ترد تقسیم می‌کنیم(لینک):برخلاف انتظار ما این‌بار این برنامه ۸ ثانیه زمان می‌بره تا اجرا بشه. یعنی استفاده از ترد نه تنها کمکی به ما نکرده بلکه سرباری هم به برنامه اضافه کرده! دلیل‌اش هم واضح باید باشه، چون گیل اینجا جلوی اجرای ترد‌ها به صورت موازی رو از ما گرفته.توی کارهای I/O bound هم گیل‌ بین ترد‌ها در حال جابجایی هست اما چون ترد‌ها بیشتر زمان‌شون رو منتظر گرفتن جواب‌هایی از جنس I/O هستند، تاثیر گیل خیلی به چشم نمیاد.چرا گیل برداشته نمیشه؟چون پایتون  از C extensionهای مختلفی استفاده می‌کنه که خیلی‌هاشون thread-safe نیستند و از طرفی حذف گیل مساوی هست با افزایش زمان اجرای برنامه‌های single thread و برنامه‌های I/O bound.اگر بازم دوست دارید بیشتر راجعبه گیل بدونید این ویدیو از آقای David Bazely می‌تونه خیلی به شما کمک کنه: لینک.کی باید از مالتی ترد استفاده کرد؟با توجه به توضحیات بالا، ترد‌ توی پایتون باید برای کار‌های خیلی ساده استفاده بشه. کارهایی که خیلی زمان پردازنده رو نگیرند یا خیلی خیلی زمان کوتاهی رو به‌خودشون اختصاص بدن. به صورت خیلی مختصر میشه گفت برای کارهای زیر می‌تونه استفاده بشه:Responsiveness GUISmall tasks such as (reset password in web-applications)Multi-threaded case for i/o bound programsSingle-threaded case for CPU bound programsجمع‌بندیهدف از این قسمت، آشنایی با چالش‌‌های موجود در پایتون در بخش Parallelsim بود. در قسمت بعدی راه‌کارهایی برای حل این چالش رو بررسی می‌کنیم. این راه‌کارها عموماً یا استفاده از چندین پراسس به جای ترد یا رفتن به سمت به سمت مفاهیمی مثل Co-operative multi-tasking هست که در رابطه با این مفاهیم توی قسمت‌ بعدی بیشتر صحبت می‌کنیم.اگر از این قسمت خوشتون اومده، حتما نظرتون رو در بخش نظرات بنویسید و همین‌طور این آموزش‌ها رو با دوستای پایتونی خودتون به اشتراک بذارید.از اینجا کجا بریمدر پایین‌ هم منابع مختلفی که به من در نوشتن این آموزش کمک کردند رو آوردم و هم لینک‌های مفیدی که می‌تونید تو هر بخش چیزهای بیشتری رو یاد بگیرید.کدهای استفاده شده در این قسمت:https://github.com/GreatBahram/OnceForEver/tree/master/code_snippets/parallelism/part1-threadingترد‌ها در پایتون:https://www.geeksforgeeks.org/multithreading-python-set-1/https://en.wikipedia.org/wiki/Thread_(computing)https://pymotw.com/3/threading/چندتا ترد باید بسازم؟https://askubuntu.com/questions/668538/cores-vs-threads-how-many-threads-should-i-run-on-this-machineمعرفی ThreadPoolhttps://www.blog.pythonlibrary.org/2016/08/03/python-3-concurrency-the-concurrent-futures-module/https://pymotw.com/3/concurrent.futures/آشنایی بیشتر با گیل و فلسفه‌ وجودیِ اونhttps://realpython.com/python-gil/https://callhub.io/understanding-python-gil/https://stackoverflow.com/questions/29270818/why-is-a-python-i-o-bound-atask-not-blocked-by-the-gilhttps://softwareengineering.stackexchange.com/questions/186889/why-was-python-written-with-the-gil</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Wed, 14 Nov 2018 11:13:10 +0330</pubDate>
            </item>
                    <item>
                <title>یک‌بار برای همیشه - Context manager</title>
                <link>https://virgool.io/@GreatBahram/once-for-ever-context-manager-qqqbqxgryxk5</link>
                <description>سلام به همه پایتون‌ دوستانِ عزیز! توی این قسمت از یکبار برای همیشه سراغِ Context managerها رفتیم. در یک‌بار برای همیشه  بحثی رو مطرح می‌کنیم که خیلی در نگاه اول شاید راحت بنظر نرسه، و این‌جا  سعی می‌کنیم با بیان ساده‌تر و مثال‌های خیلی خیلی ابتدایی اون مطلب رو به راحتی به مخاطب انتقال بدیم.مقدمهمدیریت منابع همیشه یکی از مهم‌ترین وظیفه‌های سیستم‌عامل بوده، اما بعضی اوقات پیش‌میاد به هر دلیلی منبع‌استفاده شده رو به سیستم عامل پس ندیم و  اینجاست که context managerها با یک syntax خیلی دوست داشتنی به کمک ما میان! با کمک context manager ‌ها مطمئمن می‌شیم هر دری رو که باز کردیم حتما می‌بندیم!فرض کنید توی برنامه‌مون رفتیم یک فایل رو باز کردیم به ازای اون فایل ما یک file descriptor رو مصرف کردیم. منابع همیشه توی دنیا محدود بودن و  توی هر سیستم‌عامل هم این طور هست.  این محدودیت باعث میشه یک سری قوانین توی سیستم عامل به کاربران یا برنامه‌ها اعمال بشه. به عنوان مثال هر پروسس تا یک تعداد محدودی از فایل‌ها رو  در یک زمان حق داره باز کنه . اگر از سیستم‌عاملِ *یونیکسی استفاده می‌کنید با دستور زیر این تعداد رو می‌تونید ببینید: توی عکس بالا این تعداد ۱۰۲۴ عدد هست، یعنی هر برنامه حداکثر می‌تونه ۱۰۲۴ فایل رو یک زمان باز کنه. حالا کافیه یک برنامه خیلی ساده بنویسید که بیشتر از این تعداد فایل رو باز کنه و اونا‌رو هم نبنده یه چیزی شبیه پایین: اینجاست که پایتون خطای  &#x60;OSError&#x60; رو به ما میده!جدایی از اینکه امکان تغییر این محدودیت‌ها برای کاربر وجود داره، مشکل اصلی اینِ که ما کلی فایل رو باز کردیم اما هیچ‌کدوم رو سعی نبستیم. حالا برای مطمئن شدن کافیه این‌بار همه فایل‌هایی رو که باز کردیم  ببندیم، با هم ببینیم: همون‌طور که می‌بینید با بسته شدنِ منبع‌مون همه‌چی به خیر و خوشی تموم شد. اما خب توی دنیای واقعی هزار و یک اتفاق ممکن هست رخ بده. ممکنِ وسط برنامه Exceptionای رخ بده و .... . بهمین خاطر معمولاً توسعه‌دهنده‌ها دنبال یک روش بهتر برای مدیریت منابع می‌گردن که مطمئن بشن همیشه اینکار به درستی انجام میشه. توی زبان‌های برنامه نویسی دیگه ( ناگفته نمونه توی پایتون ۲ همه تا یک مدت از این روش استفاده میشد) از try-except-finally برای این‌کار استفاده میشه. معمولاً برای کار با هر منبع ما یک سری کارهای اولیه انجام میدیم مثل اینکه به اون منبع خاص وصل بشیم (اسم این مرحله رو می‌ذاریم setup ) و بعد از این کار، کار خودمون روانجام می‌دیم(اسم این بخش رو هم می‌ذاریم do_something) و در نهایت ارتباط‌مون رو با منبع قطع می‌کنیم (اسم این بخش از کار رو می‌ذاریم teardown). با این تفاسیر اگر بخوایم گفته‌های بالا رو مدل کنیم یه چیزی شبیه پایین میشه:از اون‌‌جایی که پایتون یک زبان برنامه نویسی باحال هست؛ راه‌حلِ خیلی باحالیم برای مدیریت منابع معرفی کرده. این راه‌حل از بس باحال بوده توی خیلی از بخش‌های دیگه هم استفاده میشه و باعث شده بگیم context manager رو می‌تونید توی هر بخشی که لازم هست در ابتدا یک زیر ساختی فراهم بشه (setup) و بعد از اینکه کارمون تموم شد و  اون زیرساخت بسته یا نابود بشه (teardown) استفاده بشه. با این تعریف شما می‌تونید تو خیلی از جاها علاوه بر باز و بسته کردن یک فایل این دوستمون رو به کار ببرید.مثلاً وقتی می‌خواید بتونید توی دیتابیس امکان درج اطلاعات وجود داشته باشه پیش‌نیازش این هست که بهش وصل بشید و در پایان هم، ارتباط رو به درستی قطع کنید. مثالِ دیگه اجرای Transaction که بازم توی دیتابیس هست که سازوکاری مشابه فوق داره. توی این قسمت تاجایی که بشه سعی می‌کنیم مثال‌های مختلف رو به شما دل‌باخته‌های پایتون نشون بدیم تا ملکه‌ی ذهنتون بشه و هر کجا که به چیزی شبیه Context manager نیاز شد، سریع یه دونه تعریف کنید.معرفی مرسوم‌ترین شکل Context manager که(ممکنِ از قبل باهاش آشنا باشید) وقتی هست که  یک فایل رو باز می‌کنیم تا محتویات اون رو بخونیم. توصیه میشه (اکیداً!) که هر موقع می‌خواید یک فایل رو باز  کنید و هر کاری رو باهاش انجام بدید با with این‌کار رو انجام بدید.نحوه استفاده از context manager خیلی ساده‌اس یک قالب کلی داره: همون‌طور که می‌بینید با with به پایتون می‌گیم که می‌خوایم از یک Context manager استفاده کنیم، یک بخش اختیاری داره که داخل  [] قرار دادیم که  در واقع داریم یک اسم دیگه برای context manager اونجا می‌ذاریم ( این‌بخش که اختیاری هست موقع ساختن context manager باید پیاده‌سازی شده باشه) و تا وقتی که داخل فضای تورفته( ایندنت شده) هستیم به منبع‌ مورد نظر وصلیم و به محض خروج از فضای تور رفته اتصال ما به منبع به صورت خودکار قطع میشه .تو قسمت Decoratorها یادتونِ گفتیم @ نماد decorator هست؟ اینجا هر کجا with دیدید یعنی داریم با context manager کار می‌کنیم. فرض کنید قصد خوندن یک فایل رو داریم، برای خوندش اینجوری عمل می‌کنیم: اینکار چه مزیتی به روش قبلی داره؟ تنها مزیت‌اش اینِ که اینجا context manager قبول مسئولیت کرده که ما وقتی کارمون تموم شد( از فضای تو رفته (ایندنت شده) بیرون رفتیم) فایل رو خودش ببنده و این کار در حقیقت این کار توی تابع open تعریف شده.اگر می‌خواستیم این کار رو خودمون انجام بدیم معادل با کد پایین می‌شد: تعریف Context managerبرای بررسی بیشتر بریم خودمون کارِ تابع open رو انجام بدیم! برای تعریف context manager معمولاً از یک کلاس برای تعریف‌اش استفاده می‌کنیم. اما پایتون چطوری فرق این کلاس با کلاس‌های عدی رو می‌فهمه؟ اساساً برای ساخت یک context manager دو تا متد الزامی هست:ساز‌وکاری که بهش بگیم به محض ساخت context manager این کار رو برای ما انجام بده، که متد __enter__  مسئول انجام این کار هست.سازوکاری که از طریق اون موقع خروج مطمئن بشیم همه‌چی درست و تمیز بسته میشه. این کار رو متد  __exit__برای ما انجام میده.فرض کنید بخوایم کار تابع open از طریق context manager خودمون پیاده‌سازی کنیم:اول از همه توی متد __init__  اسم فایل و مد باز کردن فایل رو می‌گیریم. بعدش توی متد __enter__ فایل مورد نظر رو باز کردیم و اون به عنوان خروجی return کردیم. هرچیزی که اینجا return بشه اون چیزی هست که کاربر می‌تونه از طریق as myfile بهش دسترسی داشته باشه.در نهایت کارهایی که می‌خوایم موقع خروج انجام بشه رو توی __exit__ انجام دادیم که توی این مثال یعنی فایل باز شده رو ببند.اما یک نکته‌ای که بین این همه کد ممکن هست فراموش بشه خوانایی کدمون هست. بیایید یه مقایسه‌ای بین دو حالت استفاده معمولی از context manager و وقتی که داریم از with استفاده می‌کنیم داشته باشیم. توی بخش بالا فرض کردیم که چیزی به اسم withوجود نداره و در بخش پایین همون کار رو با with انجام دادیم:پس الان شاید برای شما واضح‌تر شده باشه که چرا خیلی از ماژول‌های پایتون این قابلیت رو به‌خودشون اضافه کردن.متدِ __exit__ ورودیی داره که برای مدیریت خطا‌هایی که ممکن هست رخ بده استفاده می‌شه. مثلاً بر حسب نوع خطایی که رخ داده، کار مخصوص به اون رو انجام بدیم. که ما فعلاً برای سادگی مثالمون ازش استفاده نکردیم.نکته: متغیرهایی که داخل with استفاده میشن بعد از with هم قابل استفاده هستند، یعنی متغییر محلی نیستند! یک مثال خیلی مرسوم دیگه می‌تونه وصل شدن به دیتابیس باشه. برای سادگی کار دیتابیس SQLite رو مورد استفاده قرار می‌دیم و قصدمون ساخت یک جدول برای ذخیره‌ی داده‌هامون و درج توی اون هست. این کار رو به صورت عادی اینجوری انجام میشه:حالا با context manager اولش کلاس پایین رو تعریف می‌کنیم:   و در ادامه‌ی زندگی، هر بار که خواستیم با دیتابیس کار کنیم ، اینجوری (باکلاس) بهش وصل می‌شیم:در حقیقت دیگه از تکرار مکررات به بهترین نحوه ممکن جلوگیری کردیم!خاطر‌تون هست توی بخش Decorator یک timer تعریف کردیم که زمان اجرا شدنِ یک فرآیند رو برای ما اندازه‌گیری می‌کرد (؟) این‌بار همین کار رو با Context manager می‌خوایم انجام بدیم:خروجی کد بالا میشه:اما همه‌ی مثال‌های بالا یک ایراد اساسی دارند و اون این هست که ما به هیچ‌عنوان خطا‌هایی که ممکن هست رخ رو بده رو مد نظر قرار ندادیم!متد __exit__ سه تا پارامتر ورودی می‌گیره برای مدیریت خطا‌ها به کار می‌رن:پارامتر اول exctype که نوع خطاری رخ داده شده رو مشخص می‌کنه.پارامتر دوم مقدار خطای هست  که صورت گرفته و اسمش رو  value می‌ذاریم.پارامتر سوم traceback خطای رخ داده شده است.حالا به عنوان مثال می‌خوایم متدِ __exit__ رو برای کلاسِ Timer تغییر بدیم تا بتونه خطاها رو دریافت کنه:حالا برای تستِ context manager بالا، خودمون قصدا یک خطا رو ایجاد می‌کنیم تا خروجی هر متغییر رو ببینیم:انتظار میره خروجی پایین رو ببنید: اگر براتون سوالِ که چرا پایتون Exception رو raise نکرده همه چی به return True آخرِ متد __exit__ بر می‌گرده. در حقیقت متد __exit__ یا باید False یا True رو برگردونه.با False بودن داریم به پایتون می‌گیم که Exception رو به کاربر برگردون (اگر چیزی رو return نکنیم به صورت پیش‌فرض False در نظر گرفته میشه).اما موقعی که True باشه به این معنی هست که خطا رو نادیده بگیر (suppress). و نهایتاً حواستون باشه هر چیزی بعد از raise بیاد اجرا نمیشه یعنی به raise که رسیدیم دیگه متد __exit__ اجرا شده!مثال دوم context manager مربوط به SQLite رو تغییر میدیم به نحوی که مدیریت خطا را انجام بده. توی جدولی که تعریف کردیم، ایمیل کاربر رو به عنوان یک چیز unique در نظر گرفتیم درنتیجه اگه کاربر قصد داشته باشیم یک کاربر جدید رو با ایمیل قبلی اضافه کنیم، به ما خطا میده. بریم برای مدیریت خطا متد  __exit__  رو برای DBHelper تغییر بدیم که یک پیغام مناسب توی همچین مواقعی به کاربر نشون بده: حالا می‌ریم که کد پایین رو اجرا کنیم:که با خروجی پایین مواجهه می‌شیم:خوشبختی با contextlibچیزایی که تا الان یاد گرفتیم شامل معرفی context manager، نحوه ساخت یک context manager و مدیریت خطا در context managerها بود. از اونجایی که  این مفهوم خیلی کاربردهای زیادی داره، در نتیجه یک ماژول برای تسهیل در روند استفاده از Context managerها هم وجود داره که اسمش contextlib هست. در ادامه می‌ریم که یک مرور روی  توابع پرکاربردِ این ماژول داشته باشیم.تعریفِ ساده‌تریکی از چیزای باحالِ ماژول contextlib، داشتن یک decorator برای ساده‌تر کردن ساخت context manager هست. این decorator باید به همراه یک generator استفاده بشه. اگه یادتون باشه گفتیم generator تابعی هست که به جای return از yield استفاده می‌کنه.نحوه استفاده از این decorator اینجوری هست که هرچیزی که قبل از yield باشه رو به عنوان __enter__  در نظر می‌گیره و هرچیزی بعدش باشه __exit__ می‌شناسه(آموزش Decorator لینک، آموزش Generator لینک).مثال: با استفاده از decorator ماژولِ contextlib تابعی بنویسیم که محتویات فایل رو بخونه:مثال دوم dbhelper و نحوه کنترل خطا در این بخش:همون‌طور که می‌بینید کنترل و مدیریت خطا‌ها با روش‌های قدیمی انجام میشه. فقط اینجا اگر بخواهید خطای رخ داده شده مثل وقتی که توی کلاس context manager به کاربر انتقال داده شد منتقل بشه اون خطی که کامنت شده &#x60;raise&#x60; رو باید بنویسید.کلاسِ ContextManagerماژول contextlib یک کلاس هم داره با اسم ContextDecorator که می‌تونید اون رو به کلاس خودتون به ارث بدید که مزیت‌اش این هست که context manager ای که با این کلاس ساخته بشه به عنوان decorator هم می‌تونه استفاده بشه!تابع closingاین تابع خودش یک context manager هست که یک ورودی می‌گیره و موقعی که خروج به صورت خودکار اگر اون ورودی تابع close داشته باشه اون رو صدا می‌زنه، مثلاً: تابع suppressاین یکی خیلی چیز باحالی هست، فرض کنید می‌خواهید یک فایل رو حذف کنید اما مطمئن نیستید که وجود داره یا نه، چطور این کار رو می‌کنیم؟اما با کمک suppress خیلی خواناتر و راحت‌تر میشه این کار رو انجام داد:در حقیقت suppress به عنوان ورودی می‌تونه چندین Exception بگیره و اگر هیچ‌کدوم از اونا رخ نده کار مورد نظر رو انجام میده، اگر خطا رخ بده همه‌چی رو بیخیالش میشه.جمع‌بندیهدف ما از این قسمت آشنایی با context manager بود، این دوست خوبمون هم امکان مدیریت منابع بهمون می‌ده و هم می‌تونه باعث خواناتر شدن کد بشه. امیدوارم از این قسمت لذت برده باشد و همراه خوبی برای آینده‌تون باشه. کدهای استفاده شده در این آموزش رو از طریق این لینک می‌تونید به دسترسی داشته باشید.از اینجا کجا بریممعرفی کامل ماژول contextlibhttps://docs.python.org/3/library/contextlib.html
https://pymotw.com/3/contextlib/معرفی context managerhttp://arnavk.com/posts/python-context-managers/
https://alysivji.github.io/managing-resources-with-context-managers-pythonic.html</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Sat, 20 Oct 2018 18:33:36 +0330</pubDate>
            </item>
                    <item>
                <title>یکبار برای همیشه ـ‌ Iterators</title>
                <link>https://virgool.io/@GreatBahram/once-for-ever-iterator-generator-jkgkk1s2dncj</link>
                <description>تصویر Iteratorها در طبیعتسلام به همه پایتون‌ دوستانِ عزیز. توی این قسمت از یکبار برای همیشه سراغِ Iterator و شکل ساده‌تر اون‌ها Generatorها رفتیم. در یک‌بار برای همیشه بحثی رو مطرح می‌کنیم که خیلی در نگاه اول شاید راحت بنظر نرسه، و این‌جا سعی می‌کنیم با بیان ساده‌تر و مثال‌های خیلی خیلی ابتدایی اون مطلب رو به راحتی به مخاطب انتقال بدیم. مقدمهعکس بالا یک کوآلا رو میبینم که از بومی‌های استرالیاست و معروفِ به تنبلی؛ میگن نه تنها روزی بیست ساعت می‌خوابه، بلکه یه مقدار برگ هم توی لپ‌ش قایم می‌کنه واسه میان‌وعده! نکته جالب اینجاس که Iterator و generatorها هم یه همچین نقشی توی پایتون دارن. بازم مثل همیشه یک سری کلمات کلیدی داریم که اول اونارو معرفی می‌کنیم تا ادبیات همه‌مون برای ادامه‌ی کار یکی بشه. کلمه Iteration: هر موقع شما با یک داده‌ای طرف باشید که شامل چندین مقدار باشه و هر دفعه یکی از مقدارهاشو بگیرید دارید iteration می‌کنید. مثل حلقه‌ها که هربار یک مقدار از یک داده‌ی رو به شما میده فرض کنید یک فایل رو باز کردید و هربار یک خط از اون رو می‌خونید. کلمه Iterable: روی هر چیزی نمیشه iteration کرد، توی پایتون شما روی چیزی می‌تونید Iterate کنید که یکی یا هر دوی این متد‌ها رو داشته باشه: __iter__ و __getitem__. به هر آبجکتی که این ویژگی‌ها رو داشته باشه بهش می‌گیم Iterable چون می‌تونیم روش حلقه بذاریم هر بار یک آیتم رو بگیرم تا به آخرین آیتم برسیم.کلمه Iterator: اصل جنسِ! بدون در نظر گرفتن تعریفش، هر آبجکتی که متد __next__ داشته باشه Iteratorهست. مثال:‌چون متد __next__ رو داره پس می‌تونیم تابع next رو روی اون صدا بزنیم تا مقدار بعدی رو به ما بده. یک نکته  هر آبجکتی که متد __iter__ داشته باشه یعنی قابلیت تبدیل شدن به Iterator رو داره و اگه بخوایم تبدیلش کنیم به Iterator می‌تونیم به یکی از دو روش پایین عمل کنیم:توی خط آخر منظور من این بوده که خودِ numbers چون Iterator نیست پس صدا زدن next روی اون بی معنیِ. اما اینکه چرا پس ما میتونیم حلقه بذاریم و هربار یک ایتمش رو بگیریم به خاطر متد __getitem__ هست.انگیزه ما از یادگیری: Iteratorها و فامیل خیلی نزدیکش Generatorها توی خیلی از بخش‌های پایتون به کار رفتن من جمله: for loopslooping over a text filelist, dict and set comprehensionsbuilt-in functions like filter, zip, map, ...tuple unpacking and etc. تا اینجای کار بیشتر شبیه کلاس درس فلسفه شد و هدف من این بود که به یک حسی از Iteratorها و کلمات مهم این حوزه برسیم اما بریم سراغ اصل کار که عینِ آدم اینارو معرفی کنیم و بگیم کجاها کاربرد دارن.بخش اول - Generatorخب، Generatorها در حقیقت خیلی شبیه توابع معمولی هستند با این تفاوت که دیگه از return استفاده نمی‌کنیم و به جاش از yield (بخونید ییِلد ر.ک به لینک) استفاده می‌کنیم. فرض کنیم یه تابع داریم به اسم countdown که شروع می‌کنه می‌شماره تا به صفر می‌رسه. این رو توی دوحالت Generator و تابع معمولی تعریف می‌کنیم:‌بریم از این دو تا تابع استفاده کنیم ببینیم چه فرق‌هایی دارند: تابع اول به محض فراخوانی تمام کارش رو انجام داده و خروجی رو داخل متغییر numbers ریخته. برعکس اون تابع دوم انگار هیچ کاری نکرده فقط انگار یک  آبجکتی به نام Generator برگردونده:‌ تابع next یک  Generator  (یا یک Iterator) رو به عنوان ورودی می‌گیره و مقدار بعدی اون رو بر می‌گردونه. این کار با کمک yield صورت می‌گیره. تابع تا اون‌جایی اجرا میشه که به yield میرسه و همون‌جا متوقف میشه. دفعه بعدی که next رو صدا می‌زنیم، دوباره همه کار‌هارو انجام میده تا دوباره به yield میرسه. این کار اینقدر تکرار میشه تا دیگه چیزی برای yield کردن نمی‌مونه و اون موقع است که خطای StopIteration میده.نکات مهم:‌ چیزی که هست Generator دقیقاً مشابه کوآلا داره عمل می‌کنه با تنبل‌ترین شکل ممکن داره کار می‌کنه. اگه دقت کرده باشید برخلاف یک تابع معمولی، این شکل از توابع داره وضعیت رو بخاطر می‌سپاره (به قول فرنگیا Resumable function)،‌ هربار که صداش می‌کنیم دوباره از اول اجرا نمی‌شه بلکه ادامه کارش رو اجرا می‌کنه.خیلی memory efficient هست چون در هر لحظه یک خروجی بر می‌گردونه در صورتی که شکل تابع اول اگه محاسبات بالایی داشته باشیم باید صبر کنیم تا کل کار تموم شه و بعد به خروجی دسترسی داشته باشیم.بعضی از دوستان معتقدند که استفاده از Iterator و Generator باعث میشه کد ما خواناتر بشه. برای توضیح دادن این بخش فرض کنیم قصد داریم که تابع سری فیبوناچی رو به صورت Generator پیاده‌سازی کنیم.حالا اگه یکی به ما گفت مثلا من ده عدد اول سری فیبوناچی رو می‌خوام چی؟ تو حالت اول که سریع می‌ریم داخل تابع یک متغییر تعریف می‌کنیم و میشماریم اگه ده شد بزن بیرون. اما این راه‌حل خیلی قشنگ نیست، اگه بخوایم فانکشنال فکر کنیم می‌گیم همین حالت که هست باشه، با ابزار دیگه این کار رو انجام بدیم. اینجاست که یک ماژول خیلی باحال به اسم itertools به کمک ما میاد( اگه دنبال مثال بیشتری برای این بخش هستید هر تابعِ داخل itertools یک مثال هست).مثال اول:‌ده تا عدد اول فیبوناچینکته: هر موقع بخواهید به همه مقادیر یک Generator یا Iterator دسترسی داشته باشید کافیه مشابه مثال بالا اون رو تبدیل به list کنید.مثال ۲: اعداد سری فیبوناچی را بدست بیاریم که  که بزرگتر از صد هستندتابع dropwhile دو ورودی می‌گیره یک شرط پیش‌بینی هست و دومی iterable آبجکت.مثال ۳: برعکس‌اش هم هست، اونایی که کمتر از صد هستند رو بده:‌این ماژول خیلی چیز‌های باحالی داره مثلا اگه می‌خواهید تمام حالتهای ترکیب چند کاراکتر رو بگیرید و هر بار به یک آیتم دسترسی داشته باشید  میتونید از  permutations کمک بگیرید. یک تابع خیلی باحال به اسم product داره که حتماً بهش نگاه بندازید. آخرین مثال برای تاکید بیشتر! هدف استفاده از Generator باید و باید در راستای کاهش مصرف منابع باشه، وقتی که با چیز‌های بزرگ از حیث منابع سروکار داریم. فرض کنیم قصد داریم یک حمله Brute-Force اجرا کنیم که رمز از سه رقم تشکیل شده. در حالت عادی این برنامه چیزی شبیه پایین میشه: انتظار ما این‌ هست که با پیدا کردن عدد مورد نظر برنامه متوقف بشه ولی خب این کار صورت نمی‌گیره و حلقه‌ها تا آخرین حالت ممکن اجرا میشن( حتما این بخش رو خودتون بنویسید و اجرا کنید)،‌ این در صورتی  هست که با Generatorها مطمئنیم به محض اینکه عدد مورد نظر پیدا شد دیگه محاسبات بیهوده نداریم. اما Iteratorها! خُب، اگه یادتون باشه گفتیم Generator یک شکل خیلی خیلی ساده شده‌ی Iteratorها هستند. دقیقاً مشابه این هست که داریم یک کار رو از صفرِ صفر شروع می‌کنیم (Build from scratch). مثال سری فیبوناچی رو یادتون هست که با Generator نوشتیم؟ این بار می‌ریم اون رو با یک تغییر کوچیک به سبک Iterator بنویسیم و می‌فهیم منظورمون از Build from scratch چیه؟اولین تغییری که به چشم میاد،‌ استفاده از کلاس هست به جای مثال‌های قبلی که همگی تابع بودند. و دو تابع خاص منظوره رو استفاده کردیم که عبارتند از :‌ ‍‍__iter__ و __next__.تابع __iter__ در حقیقت وقتی صدا زده میشه که ما تابع iter روی این یک آبجکت از این کلاس صدا بزنیم. شما ممکنه بگید که ما این‌کار رو تا الان نکردیم؛ حق با شماست. این کار معمولاً خودکار انجام میشه. مثلاً وقتی دارید از حلقه استفاده می‌کنید خود حلقه for این کار رو انجام میده. متد __next__ هم وقتی صدا زده میشه که تابع next روی اون اجرا کنیم. اگه دقت کنید میبینید که دیگه خبری از yield نیست! حتی StopIteration رو هم خودمون تعریف کردیم که این خطا رو بده! فکر کنم با مثال خیلی راحت‌تر باشه این حرفا:حالا فکر کنم بیشتر به قدرت yield پی‌ بردیم، ساخت یک Iterator با Generator بسیار راحت‌تر میشه. نکته کلیدی قدرت سفارشی‌سازی Iterator است در مقابل سادگیِ Generator و resource-friendly بودن این دوتا دوست عزیز ما در پایتون!جمع بندی‌امیدوارم این قسمت یک‌بار برای همیشه حق مطلب رو بخوبی ادا کرده باشه. اگه کسی رو می‌شناسید که دوست داره پایتون رو به صورت حرفه‌ای یاد بگیره یادتون نره این پست‌ها رو باهاش به اشتراک بذارید. خیلی ممنون تا قسمت بعدی یک‌بار برای همیشه خدانگهدار!از اینجا کجا بریماگر بازم حس می‌کنید نیاز به مطالعه بیشتر در این زمینه دارید: http://www.diveintopython3.net/generators.htmlhttp://www.diveintopython3.net/iterators.html* اگر از itertools خوشتون اومده حتما این لینک رو هم دنبال کنید کلی مثال جذاب داره!https://realpython.com/python-itertools/</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Thu, 04 Oct 2018 23:12:49 +0330</pubDate>
            </item>
                    <item>
                <title>یکبار برای همیشه Decorator</title>
                <link>https://virgool.io/@GreatBahram/once-for-ever-decorator-pud0djkbgill</link>
                <description>This is the real decorator in Python!پیشگفتارسلام به همه متفکرین و محققین پایتون!اگر عمری باقی باشه قصد داریم یه چرخی توی مفاهیم بنیادی پایتون بزنیم، اولین جلسه هم با Decorator می‌خوایم شروع کنیم. این مفاهیم مهم‌ترین ایرادی که میشه بهشون گرفت این هست که در نگاه اول پیچیده بنظر می‌رسند. توی مجموعه یکبار برای همیشه سعی شده که این سختی‌ها تا جایی ممکنه ساده‌سازی بشن و با مثال‌های مختلف این مطالب، تعریف بشن.مقدمهاما decorator چیه؟ تعریف خیلی ساده اش اینه که decorator ها امکان توسعه و تغییر رفتار یک چیز قابلِ فراخوانی را به ما میده. توسعه یا تغییری مد نظر ما هست که باعث تغییر در اون چیزِ قابل فراخوانی نشه! یعنی فقط یک decorator به کد ما اضافه بشه. اما منظور ما از چیزی که قابلیتِ فراخوانی داره چیه؟ این چیز‌ها سه نوع هستند: توابع، متد‌ها و کلاس‌ها. به چه چیزی می‌شه گفت قابلیت فراخوانی داره؟ هر چیزی که اگر اون رو به تابع callable بدیم خروجی True برگردونه.مثلاً تست کنید: callable(print) # which means Can I call print function?توابع و متد‌ها به صورت پیش‌فرض قابلیت فراخوانی دارند. یعنی اسمشون رو می‌نویسیم و بعدش که پرانتز می‌ذاریم به این معناست که اون‌ها رو صدا زدیم یا کالِشون کردیم. آیا کلاس هم قابلیت کال(call) کردن داره؟ بله! اگه زمان تعریف کلاس متد &#x27;__call__&#x27;  رو برای اون کلاس تعریف کنیم دقیقا مشابه یک تابع امکان فراخونی پیدا می‌کنه.خیلی دور نشیم از بحث اصلی اما آیا واقعا نیازه من برم بفهمم decorator چی‌هست؟ چند از کاربرد‌های اون رو نشون بده حداقل.بسته به اینکه چه استفاده کننده‌ای از پایتون هستید، مثال‌ها میتونه مختلف باشه.ماژول atexit  یک برنامه ساده‌اس که میگه وقتی از برنامه خارج شدی چیکار بکن، این ماژول رو به دو صورت قابل استفاده است، حالت اول که تابع خودمون رو تعریف کردیم بعد به atexit گفتیم هر موقع خواستی از برنامه خارج شدی قبلش این تابع رو اجرا کن.حالت دوم که برای ما حائز اهمیتِ، با استفاده از decorator هست. این علامت «@» رو هرکجا توی پایتون دیدید، سریع decorator باید تو ذهنتون بیاد. یادتونه موقع تعریف گفتم decoratorها امکان توسعه و تغییر میدن. این یک مثال از توسعه هست. در حقیقت ما بدون تغییر تابع خودمون موفق شدیم اون تابع رو با استفاده از decorator به نحوی توسعه بدیم که موقع خروج تابع ما اجرا بشه.پس میشه اینجوری خلاصه‌اش کرد، ما به یک decorator یک چیزی(تابع، متد و یا کلاس) رو میدیم و اون چیز رو decorator تغییر میده و تغییر یافتشو به ما بر میگردونه. سینتکس کلی‌ رو میشه اینجوری تعریف کرد.@our_decoratordef our_function(args):....که برابر هست با کد پایین(تقریباً):def our_function(args):....our_function = our_decorator(our_function)خیلی از جاها شما ممکنه decoratorها رو دیده باشید. مثلا اگه به شی‌گرائی علاقه‌مند باشید staticmethod@ ، @classmethod، و یا property@  مثالهایی از این قبیل هستند. اگه توسعه دهنده سمت سرور هستید مثلا فریم‌ورک فلسک پر هست از decorator که بدون اونا زندگی چقدر سخت میشه! لیستی از decoratorهای معروف پایتون: لینک!اما تعریف و تمجید از آقای decorator بسه، بریم سراغ اینکه چطور یه دونه بنویسیم و ازش استفاده کنیم. پیش از این باید چندتا از پیش‌نیاز‌های decorator که مفاهیم اولیه پایتون در رابطه با توابع هستند رو توضیح بدم.توابع در پایتونیک جمله‌ی خیلی مشهوری در پایتون وجود داره که میگه «توابع در حقیقت &quot;First-Class&quot; آبجکت هستند». یعنی توابع توی پایتون به تمامی حالت‌ها قابل استفاده هستند. برخلاف بقیه چیز‌ها که ممکنه اینجور نباشن. به همین خاطر بهشون میگیم First-Class (بهترینمون هستند). ویژگی‌های توابع عبارتند از:توابع در پایتون مثل هر چیز دیگه یک آبجکت حساب میشن. در نتیجه می‌تونیم مثل یک آبجکت اونارو به متغییر انتصاب کنیم:اگر از تابع id بپرسیم که این‌دوتا تابع به چه آدرسی از حافظه اشاره می‌کنن؟ جوابشون قابل تامله!هر دوی اونا به خونه از حافظه اشاره می‌کنن و وقتی تابع اصلی رو پاک می‌کنیم هنوز توی اون آدرس حافظه تابع موجوده و تابع دوم به کارش ادامه میده.تابع را می‌توان به تابع‌ِ دیگر به عنوان ورودی پاس داد.توابع می‌توانند تودرتو باشند!خب اگه از زبان‌هایی مثل سی و دوستاش به پایتون مهاجرت کرده باشید، شاید اولش این یکم عجیب باشه واستون، اما خب اینجا میشه تا تعدادِ زیادی تابع تودرتو تعریف کنید. نکته اینکه قطعاً انتظار نداریم که به تابع درونی دسترسی داشته باشیم! مگر اینکه اون تابع داخلی مورد نظرمون رو return کنیم. چیزی شبیه پایین:یه چیزه دیگه هم هست، تابع داخلی میتونه به ورودی‌های تابع بیرونی دسترسی داشته باشه! چطوره مثال بالا رو طوری تغییر بدیم که متن هم همونجا بگیره و به تابع درونی پاس بده؟!آبجکت‌ها هم می‌توانند فراخوانی شوند!اگه یادتون باشه،‌گفتیم توابع توی پایتون آبجکت هستند. اما آبجکت‌ها که تابع نیستند. یعنی هر آبجکت ذاتا قابل فراخوانی نیست. اما میشه کاری کرد که آبجکت‌ها نیز قابلیت فراخوانی پیدا کنند، فقط باید این کار فعال بشه. مثال:با متد __call__ میشه این قابلیت رو به آبجکت مورد نظر داد.خب الان تمام چیز‌هایی که نیازه رو یاد گرفتیم، بریم با خود decorator آشنا شیم.معرفی Decoratorبریم اولین decorator رو تعریف کنیم، برای راحتی کار بریم یک decorator تعریف کنیم که هیچ‌کاری نمی‌کنه!خُب یک تابع خیلی ساده به اسم say_hello تعریف کردیم و یک decorator که هیچ کاری نمی‌کنه جز اینکه تابعی که بهش پاس داده شده رو برگردونه. بعدش که تابع اولیه رو اجرا می‌کنیم می‌بینیم همون‌طور که انتظار داریم هیچ‌چیزی تغییر نکرده! اگه یادتون باشه اون بالا گفتیم نماد decorator، @ هست خب یکبار با این نماد از decorator استفاده کنیم:پس تا اینجا یادگرفتیم که اولاً یک decorator خیلی پیش‌پا افتاده تعریف کنیم، ثانیاً یاد گرفتیم چطوری کاملا دستی (manually) decorator رو بکار ببریم و ثالثاً یک چیز رو اتوماتیک decorate کنیم.اما بریم واقعا با decorator یک‌کاری انجام بدیم: کاری که این‌سری انجام گرفته، این هست که ما یک decorator به اسم make_uppercase تعریف کردیم که یک تابع رو به عنوان ورودی می‌گیره و درون خوش یک تابع داره که خروجی اون تابع رو به عنوان خروجی خودش برمی‌گردونه(اصطلاحاً به توابع این‌شکلی closure(بخونید کلوژر) گفته میشه).اعمال چندین decoratorمثال: فرض کنیم قرار هست، با استفاده از چندین decorator کاری کنیم که بتوانیم تگ‌های html را به رشته موردنظر اضافه کنیم: که طبق مطالب قبلی میشه اینجوری هم تعریفش کرد:نوشتن decoratorای که آرگومان می‌پذیرد!تا این‌جای کار تابع‌هایی که نوشتیم خیلی ساده بودند، هیچ‌گونه پارامتر ورودی نداشتند (say_hello) و در نتیجه هیچ‌ مشکلی در پاس دادن پارامتر از تابع decorator (مثلا bold/italic) به تابع‌ای که قراره decorate بشه (say_hello) نبود.اما اگر تابعی که نوشتیم ورودی می‌گیره دیگه با این حالت به مشکل می‌خوریم. باید به طریقی به تابع decorator بگیم که تمام پارامتر‌هایی که بدستت میرسه رو به تابع اصلی ما هم بده. اینجاس که این دو برادر args* و kwargs** به کمک ما میان (اگه نمی‌دونید اینا چی هستن از این لینک استفاده کنید!)، یک مثال با هم ببینیم: یک مثال به عنوان جمع بندی کارتا اینجای کار گفتیم که decorator چی هست و چه‌جوری تعریفش کنیم. اما بنظرم خوبه که بریم یک مثال خوب هم باهاش ببینیم:فرض کنیم ما بی‌خبریم از اینکه ماژول‌هایی هست که به صورت خیلی دقیق به ما میگن هر تابع چقدر طول میکشه تا اجرا بشه و قصد داریم حالا که یاد گرفتیم decorator چی هست، بریم یکی تعریف کنیم با اسم timeit که بره این کار رو برای هر تابعی که خواستیم انجام بده. اول از همه تعریفش کنیم:خب دقیقاً مشابه چیزی که تا الان یاد گرفتیم، تابع رو از ورودی گرفتیم پاس دادیم به تابع درونی wrapper هرچی ورودی داشتیم هم دادیم به اون تابع، منتهی این سری، دو متغییر هم اضافه کردیم که بفهمیم چقدر زمان صرف اجرای این تابع شده. بریم از اولین دستاوردمون استفاده کنیم( یادتون که  ماژول time رو هم import کنید):تابعی که تعریف کردیم از ورودی یک عدد میگیره و به اون تعداد ثانیه متوقف میشه، همون‌طور که پیداس ما بهش گفتیم سه ثانیه متوقف شو! خروجی decorator ِای که تعریف کردیم پاینش چاپ شده.نکته‌ها:با استفاده از decorator موفق شدیم در تابع ورودی تغییر یا توسعه‌ای بدیم که بتونیم بفهمیم چقدر زمان میبره تا این تابع اجرا بشه.این کار بدون اینکه بریم تابع مورد نظر رو تغییر بدیم صورت گرفته، تصور کنید چقدر پس این decorator می‌تونه مفید باشه. از اینجا کجا بریمیک ماژولی که دارای decorator خیلی باحالی هستhttps://stackoverflow.com/questions/308999/what-does-functools-wraps-dohttps://mrcoles.com/blog/3-decorator-examples-and-awesome-python/https://gist.github.com/Zearin/2f40b7b9cfc51132851aکتاب Python Tricks صفحه ۷۴ خیلی توضیحات مفصل و کاملی در رابطه با decorator داده.کلام آخرامیدوارم که از این مطلب خوشتون اومده باشه، اگر این‌طور بوده حتما این مطلب با پایتون دوست‌های دیگه به اشتراک بذارید. تا یکبار برای همیشه‌ی دیگه خدانگهدار!</description>
                <category>GreatBahram</category>
                <author>GreatBahram</author>
                <pubDate>Sun, 09 Sep 2018 11:22:47 +0430</pubDate>
            </item>
            </channel>
</rss>