<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های مهدی</title>
        <link>https://virgool.io/feed/@liewpl</link>
        <description>سلام، من مهدی‌ام، مطالعه‌ی تخصصیم پایتونه و هر از چندی یه مقاله راجع به پایتون می‌نویسم</description>
        <language>fa</language>
        <pubDate>2026-06-15 22:15:30</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/1084705/avatar/J23WZm.jpg?height=120&amp;width=120</url>
            <title>مهدی</title>
            <link>https://virgool.io/@liewpl</link>
        </image>

                    <item>
                <title>الگوریتم Timsort</title>
                <link>https://virgool.io/@liewpl/timsort-algorithm-u41h0wv0jnax</link>
                <description>در این مقاله‌ به بررسی مفصل و جامع الگوریتم تیم‌سورت می‌پردازیم.بعد از کمی مقدمه، معرفی الگوریتم و بررسی یک تاریخچه‌ی کوتاه، گام به گام الگوریتم و تمامی سیاست‌هایی که در آن بکار گرفته شده‌اند را بررسی می‌کنیم و توابعی در CPython که در هر گام، وظیفه مرتب کردن یک لیست را دارند (list.sort) معرفی می‌کنیم.مقدمه و معرفیدر دنیای علوم کامپیوتر، مرتب‌سازی یک عملیات اساسی با کاربرد‌های بی‌شمار است. در میان انبوهی از الگوریتم‌های مرتب‌سازی، یکی از الگوریتم‌ها به دلیل کارایی، تطبیق‌پذیری و طراحی زیبا متمایز شده است: الگوریتم تیم‌سورت. این الگوریتم که توسط تیم پیترز برای زبان برنامه نویسی پایتون توسعه یافته است، به سنگ بنای پیاده‌سازی مرتب‌سازی در زبان‌ها و محیط‌های مختلف برنامه‌نویسی تبدیل شده است.ترکیب منحصر به فرد مرتب‌سازی ادغامی (Merge Sort) و مرتب‌سازی درجی (Insertion Sort) به همراه‌ بهینه‌سازی‌های مخصوص روی هر الگوریتم و بهینه‌سازی‌های تطبیقی‌، تیم‌سورت را به یکی از پیچیده‌ترین، کاربردی‌ترین و یکی از بهینه‌ترین الگوریتم‌های مرتب‌سازی تبدیل کرده است.تاریخچهالگوریتم تیم‌سورت، در سال ۲۰۰۲ توسعه یافت. این الگوریتم از نسخه‌ی 2.3 پایتون تا حدود بیست سال، الگوریتم استاندارد مرتب‌سازی در پایتون بود و از نسخه‌ی 3.11.1 به دلیل تغییراتی که در سیاست‌های ادغام آن بوجود آمد، الگورتیمی به اسم Powersort بر پایه‌ی تیم‌سورت، جایگزین آن شد.الگوریتم تیم‌سورت درزبان Java SE 7سیستم عامل Androidزبان GNU Octaveانجین V8زبان Swiftزبان Rustپیاده‌سازی شده است.چراهاتیم‌ پیترز این الگوریتم را اینگونه توصیف می‌کند:A non-recursive adaptive stable natural merge sort / binary insertion sort hybrid algorithmچرا non-recursive؟چون طبق گفته‌ی تیم پیترز: «به طور خلاصه، روتین اصلی یک بار از سمت چپ تا راست، آرایه را طی، Run‌ها را شناسایی و هوشمندانه‌ آنها را با هم ادغام می‌کند» (مفهوم Run در ادامه توضیح داده‌ خواهد شد.)چرا adaptive؟چون این الگوریتم با توجه به طول و ترتیب‌های از قبل موجود در آرایه، و همچنین بر اساس اندازه‌‌ی Runهای پیدا شده، تصمیماتی می‌گیرد تا از الگوریتم بهتری برای آن موقعیت استفاده کند.چرا stable؟چون این الگوریتم، ترتیب عناصر یکسان در آرایه‌ی اولیه را حفظ می‌کند. برای مثال اگر لیستی از این اسامی داشته باشیم:و آنرا بخواهیم بر اساس حرف اول کلمات مرتب کنیم، چنین چیزی می‌گیریم:اگر دقت کنید در لیست اولیه، straw قبل از spork آمده بود و در لیست مرتب شده هم همین ترتیب حفظ شد. به این نگهداری ترتیب اولیه‌ی عناصر، پایداری الگوریتم مرتب‌سازی می‌گویند.چرا hybrid؟چون این الگوریتم از ترکیب دو الگوریتم Merge Sort و Binary Insertion Sort برای مرتب سازی استفاده می‌کند.مقایسهمقایسه‌ی کلی بین پیچیدگی زمانی الگوریتم‌های TimSort و Merge Sort و Quick Sort و Heap Sort چنین چیزیست:اما این تحلیلِ کلی، یک سری جزئیات راجع به پیچیدگی زمانی الگوریتم را پنهان می‌کند که آن یکconstant factor اثرگذار در میزان پیچیدگی الگوریتم است.برای مثال در الگوریتم Quick Sort انتخاب مقدار left و right و pivot اثرگذاراند و در nهای کوچک سرعت را پایین می‌آورد.در الگوریتم Merge Sort هم فضایی به اندازه‌ی n + m برای ادغام کردن آرایه‌ها آن هم به صورت بازگشتی و تعداد زیاد نیاز دارد. همچنین این الگوریتم، یک الگوریتم بازگشتی‌ست و درخت بازگشتی و یک system stack برای اجرا نیاز دارد.بخاطر جابجایی‌هایی در الگوریتم Heap Sort انجام می‌شود، Locality of Reference در آن بارها نقض شده و پیشبینی‌های پردازنده‌ برای کش کردن داده‌ها را تضعیف می‌کند.پس اگر بتوانیم این constant factor را کاهش دهیم می‌توانیم سرعت بیشتری از O(nlgn) بگیریم.بررسی الگوریتم Binary Insertion Sortپیچیدگی زمانی Insertion Sort برابر با O(n^2) است و constant factor آن بسیار بسیار کوچک است؛ چون اولا inplace عمل می‌کند (پس نیازی به فضای اضافه ندارد) و ثانیا فقط بین عناصر آرایه پیمایش انجام می‌دهد (پس Locality of Reference هم در آن بسیار خوب است و پردازنده می‌تواند داده‌ها را کش کند.) در تحلیل‌های انجام شده روی الگوریتم‌ها، این الگوریتم روی تعداد ورودی ۶۴ و پایین‌تر، از الگوریتم‌های دیگر مرتب سازی سریع‌تر عمل می‌‌کند.الگوریتم Binary Insertion Sort بجای جستجوی خطی در آرایه (با پیچیدگی O(n)) در آن جستجوی دودویی انجام داده و در زمان لوگاریتمی (O(lgn)) مکان صحیح آیتم را پیدا می‌‌کند (علت استفاده از این الگوریتم در ادامه روشن خواهد شد.)با تعویض نوع جستجوی‌ این الگوریتم میزان پیچیدگی آن (حالت مورد انتظار و در بدترین حالت) تغییری نکرده و همان O(n^2) باقی می‌ماند؛ اما در CPython مقایسه‌ها (بخاطر ماهیت dynamic typed بودن زبان) نسبت به جابجا کردن آبجکت‌ها بسیار وحشتناک کند‌تر هستند.جابجا کردن آبجکت‌ها صرفا کپی کردن ۸ بایت pointer است اما مقایسه‌ها میتوانند بسیار کند باشند (چون ممکن است چند متد در سطح پایتون را صدا بزنند) و حتی در حالات ساده ممکن است بین ۳ یا ۴ تصمیم گرفته بشود:تایپ عمل‌وند چپ چیست؟تایپ عمل‌وند راست چیست؟آیا باید آنها را به یک تایپ مشخص تبدیل کرد؟چه کدی برای مقایسه این دو موجود هست؟ و...پس یک مقایسه ساده باعث تعداد بسیار زیادی C-level pointer dereference، عملیات‌های شرطی و صدا زده شدن توابع می‌شود.پس اگر ما تعداد مقایسه‌ها کمتر کنیم میتوانیم سرعت مرتب سازی را بیشتر کنیم (که با استفاده ازbinary insertion sort ما تعداد مقایسه‌ها را کم می‌کنیم.)این مرتب‌ سازی با تابع binarysort در کدهای CPython انجام می‌شود.ایده اگر آرایه را به تکه‌های کوچک تقسیم کنیم‌ (برای مثال ۳۲ تا ۶۴ تایی) و سپس آنها را جدا جدا با مرتب‌ سازی درجی مرتب کنیم و سپس همه را ادغام کنیم، می‌توانیم سرعت مرتب سازی را افزایش دهیم. با اینکار:از مرتب سازی درجی که برای تعداد کم سریع است استفاده کردیمادغام دو آرایه مرتب شده در زمان O(n) انجام می‌شودبا این کار ما توانستیم ۵ سطح از درختی در Merge sort تولید می‌شود را کم کنیم و پیچیدگی  تیم‌سورت تا اینجا چنین می‌شود:که چون اینکه پیچیدگی Binary Insertion Sort در nهای بزرگ کوچک است می‌توان از آن چشم‌پوشی کرد.حقیقت در دنیای واقعی و داده‌های واقعی معمولا آرایه‌ها اصطلاحا partially sorted هستند. این به این معناست که تکه‌هایی از آرایه از قبل مرتب هستند؛ برای مثال در این آرایه:قسمتاز قبل مرتب است.یا داده‌ها حداقل به صورت صعودی یا نزولی پشت سر هم حضور دارند؛ برای مثال در این آرایه:قسمتبه صورت صعودی و قسمتبه صورت نزولی مرتب است.الگوریتم تیم‌سورت این تکه‌های صعودی و یا اکیدا نزولی را در آرایه پیدا می‌کند و آنها را Run می‌نامد و از مرتب بودن اولیه آرایه برای افزایش سرعت استفاده می‌کند.نتیجهاگر از حقیقت قبلی استفاده کنیم و آرایه را به قسمت‌هایی صعودی و یا اکیدا نزولی تقسیم کنیم می‌توانیم درخت Merge sort حتی بیشتر از قبل هم کوتاه کنیم، و پیچیدگی را بهتبدیل کنیم. پس هر طول و تعداد Runها بیشتر باشد، مقدار x بیشتر و درخت ادغام ما کوتاه‌تر و الگوریتم سریع‌تر می‌شود.توضیح Runهاتکه‌هایی از آرایه که از قبل دارای ترتیب هستند، در این الگوریتم یک Run نام می‌گیرند. Runها میتوانند:صعودی باشند:اکیدا نزولی باشند:دلیل اینکه یک Run باید نزولی اکید باشد تا یک Run شناخته شود، اینست که الگوریتم تیم‌سورت Run‌های نزولی را به صورت درجا، برعکس می‌کند و اگر در یک Run نزولی (و نه اکیدا نزولی) دو عنصر یکسان وجود داشته باشد، ماهیت stable بودن الگوریتم نقض می‌شود. برای مثال این‌ آرایه:اگر برعکس شود:که ترتیب عناصر ۳ عوض شده است. اما اگر اکیدا نزولی باشد دیگر این مشکل وجود نخواهد داشت.نکته‌ی دیگر اینست که Runها حداقل دو آیتم دارند مگر وقتی که آخرین عضو آرایه را برای Run جدید برگزینیم.اگر عناصر آرایه رندوم باشند، بعید است که ما Runهای طبیعی (یعنی قسمتی از آرایه که از قبل مرتب شده باشد) بلندی را شاهد باشیم. اگر یک Run طبیعی تعداد عناصرش کمتر از minrun باشد (توضیح داده خواهد شد،) الگوریتم با استفاده از Binray Insertion Sort تعداد آنرا به حداقل اندازه‌ی Run می‌رساند. دلیلی که می‌توانیم از Binray Insertion Sort استفاده کنیم اینست که هر Run خودش مرتب است، پس می‌توان در آن جستجوی دودویی انجام داد.یک مثالالگوریتم برای پیدا کردن Runها چنین عمل می‌کند: فرض کنید که اندازه‌ی Runها ۳ تعیین شده است و چنین آرایه‌ای داریم:از چپ به راست حرکت می‌کنیم ۸ را جدا می‌کنیم و سراغ آیتم بعدی می‌رویم و متوجه می‌شویم که یک Run صعودی داریم:ادامه ‌می‌دهیم و به عدد ۹ می‌رسیم، چون این Run باید صعودی باشد، و حداقل طول هم ۳ است و ۹ از ۱۲ کمتر است با استفاده از Binary Insertion Sort جایگاه ۹ را پیدا می‌کنیم.عدد بعدی هم بزرگ‌تر از ۱۲ است و آن را هم به این Run اضافه می‌کنیم:عدد بعدی، از ۱۷ کمتر است و چون ما حداقل اندازه‌ی یک Run را داریم آنرا دیگر به این Run اضافه نمیکنیم و به سراغ Run بعدی می‌رویم. پس:و سپس با Binary Insertion Sort:و چون 11 از 1- بیشتر است و ما حداقل اندازه‌ی یک Run را داریم ابتدا آنرا برعکس:و به سراغ Run بعدی می‌رویم؛ که Run بعدی هم این است:که الگوریتم آنرا هم برعکس می‌کند تا صعودی شود:اگر داده‌ها رندوم باشند، اکثر Runها یک اندازه خواهند داشت که دو خوبی دارد:ادغام کردن Runهایی که اندازه‌ی برابر دارند بسیار بهینه است وما حداقل توانسته‌ایم اندازه‌ی درخت بازگشتی ادغام را به اندازه‌ی کف lg(minrun) کم کنیم.برای داده‌های واقعی هم، ما چون Runهای نسبتا بلندی خواهیم داشت توانسته‌ایم کوتاه‌ترین درخت بازگشتی ادغام را داشته باشیم و در نتیجه تعداد ادغام‌ها را کم کنیم. پیدا کردن Runها در آرایه توسط تابع count_run انجام می‌شود.کدی که به Runهای اضافه شده، عنصر اضافه می‌کند تا به اندازه‌ی minrun برسند:محاسبه‌ی minrunمحاسبه‌ی minrun بر اساس اندازه‌ی اولیه آرایه، انجام می‌شود:اگر طول آرایه‌ کمتر از 64 باشد، از Binary Insertion Sort برای مرتب کردن آن استفاده می‌شود.اگر طول آرایه توانی از ۲ بود، طبق تست‌های انجام شده تمامی اعداد ۸ و ۱۶ و ۳۲ و ۶۴ و ۱۲۸ سرعت یکسانی را به الگوریتم می‌دادند اما مثلا در اندازه‌ی ۲۵۶ تا، جابجا کردن عناصر در مرتب ‌سازی هزینه بردار و در انداز‌ه‌ی ۸ تعداد صدا زده شدن توابع هزینه‌ بردار بود. بعد از کمی مطالعه عدد ۳۲ برای minrun انتخاب شد.اما بعد از زمان زیادی یک اشکال در انتخاب این عدد پیدا شد، این مثال را ببینید:که اگر با این تعداد Run ما ادغام را انجام بدهیم، در پایان باید یک آرایه‌ی ۲۰۴۸ عضوی و یک آرایه‌ی ۶۴ عضوی را با هم ادغام کنیم که اصلا خوب نیست. اما اگر عدد ۳۳ را برای minrun انتخاب کنیم ما ۶۴ تا Run با اندازه‌ی ۳۳ داریم که برای ادغام خیلی بهتر است.سیاستی که برای محاسبه‌ی minrun در پیش گرفته شده است اینست که این مقدار از range(32, 64) به صورتی انتخاب می‌شود که N/minrun یا دقیقا توانی از دو باشد، یا اگر این ممکن نبود، اکیدا کمتر از توان ۲ باشد.این انتخاب توسط تابع merge_compute_minrun انجام می‌شود.بهتر کردن استفاده از فضا در ادغامالگوریتم ادغام در Merge sort الگوریتمی inplace نیست و برای ادغام کردن دو آرایه با طول‌های n و  m یک آرایه‌ی جدید به طول n + m نیاز دارد، اما تیم‌سورت برای inplace مرتب کردن و کمتر کردن space overhead الگوریتم مرتب سازی ادغامی از روش بهتری برای ادغام کردن دو Run استفاده می‌کند.اگر آرایه‌ای به این صورت داشته باشیم: در این روش جدید ادغام ما یک آرایه‌ی موقت به اندازه‌ی Run کوچک‌تر درست می‌کنیم و عناصر Run کوچک‌تر را در آن کپی می‌کنیم. کپی کردن‌های این چنین هم (یعنی یک تکه از یک آرایه) به بهینه‌ترین حالت در سطح پایین اجرا می‌شوند. پس حالا ما چنین چیزی داریم:چون آرایه‌ی کوچک‌تر سمت چپ بود، پس از سمت چپ‌ آرایه‌ی موقت و دومین Run شروع به ادغام کردن می‌کنیم. که یعنی:را باهم مقایسه، و برنده (عنصر کوچک‌تر) را در ایندکس صفر آرایه‌ی A می‌گذاریم. که می‌شود:سپس:که می‌شود:سپس:که می‌شود:سپس:که می‌شود:سپس:که می‌شود:سپس:که می‌شود:سپس:که در اینجا عنصر ۲۲ آرایه‌ی موقت انتخاب می‌شود. چون برای حفظ پایداری الگوریتم مرتب‌ سازی لازم است که بیست و دویی که زودتر آمده انتخاب شود:وضعیت کنونی ادغام:و حالا که عناصر آرایه‌ی موقت تمام شده، باقی عناصر باقی مانده سر جای خود هستند و دیگر مقایسه و جابجایی لازم نیست و آرایه به صورت مرتب ادغام شد:جهت ادغامدر مثال قبلی Run کوچک‌تر در سمت چپ بود و ما ادغام را از سمت چپ Run بزرگ‌تر و آرایه‌ی موقت انجام دادیم، اما اگر چنین حالتی باشد:ما چنین چیزی داریم:در این حالت که Run کوچک‌تر در سمت راست بود، ما هم تمام ادغام را از سمت راست انجام می‌دهیمکه می‌شود:و سپس:که می‌شود:و الی آخر...تابعی که عمل ادغام را شروع می‌کند، تابع merge_collapse است که در ادامه بیشتر راجع به آن توضیح داده خواهد شد.تکنیک Gallopingچنین سناریویی را تصور کنید: ما این آرایه‌ و Runها را داریم:در تکنیک Galloping، ما با استفاده از binary search مکان اولین عضو Y را در X پیدا می‌کنیم که می‌بینیم در جایگاه ۴ باید آن را بگذاریم، این یعنی تمامی عناصر قرمز سر جای واقعی و درست خود قرار دارند: در جایگاه درستی قرار دارند.همین کار را برای آخرین عنصر X نسبت به Y انجام می‌دهیم که مکان آن در جایگاه پنجم دومین Run است، این یعنی تمامی عناصر قرمز در جایگاه درستی قرار دارند.پس ما چنین آرایه‌ و Runهایی داریم:و صرفا باید الگوریتم ادغامی که بالاتر بحث شد را روی این X و Y کوچک‌تر انجام بدهیم که هم سریع‌تر است و هم فضای کمتری استفاده خواهد کرد.نکته‌ای که در تکنیک Galloping وجود دارد اینست که این روش فقط بعضی وقت‌ها فقط به نفع ماست. به این مثال دقت کنید:ابتدا مکان ۲ را در X پیدا می‌کنیم که در جایگاه دوم باید قرار بگیرد و سپس مکان ۹ را در Y پیدا می‌کنیم که در جایگاه پنجم باید قرار بگیرد.که به چنین آرایه‌ای می‌رسیم:که مشخصا هیچ بهبودی را برای ما نداشت هیچ، بلکه چندین مقایسه اضافه‌ هم با Binary Search انجام داده‌ایم.مقدار min_gallopطبق تست‌هایی که تیم پیترز انجام داده است، تعداد عنصری که باید سر جای خودشان باشند، در ابتدای الگوریتم، باید حداقل ۷ تا باشد که این عدد نام min_gallop دارد. این یعنی اگر جایگاه اولین عنصر Y را در X پیدا کنیم و ۷ عنصر در جایگاه خودشان باشند، این تکنیک موثر خواهد بود (همین برای پیدا کردن آخرین عنصر X در Y هم صدق می‌کند.)در ادغام کردن اگر حالت اول (مکان اولین عنصر Y در X) یا حالت دوم (مکان آخرین عنصر X در Y) بزرگ‌تر مساوی min_gallop بود، از این تکنیک استفاده می‌شود.بعد از هر بار موفق بودن galloping عدد min_gallop به عنوان یک تشویق برای الگوریتم، یکی کم می‌شود تا در ادامه هم بتوان از galloping استفاده کرد.حالت عکس هم چنین است که مکان پیدا شده کمتر از min_gallop باشد که یعنی این تکنیک موثر نبوده و از حالت مقایسه‌ی ادغامی ساده، یعنی عنصر به عنصر استفاده می‌شود و عدد min_gallop به عنوان جریمه یکی زیاد می‌شود.روش galloping در داده‌های واقعی که partially sorted هستند بسیار کارآمد است و تعداد مقایسه‌ها را کمتر می‌کند اما در داده‌های رندوم این روش موثر نیست و از مقایسه‌ی عنصر به عنصر استفاده می‌شود کهکد ساده‌ای دارد واز اصل همجواری (Locality of Reference) به خوبی پیروی می‌کند و پردازنده می‌تواند به خوبی داده‌ها را کش کند.در الگوریتم gallop کردن از چپ توسط تابع gallop_left و gallop کردن از سمت راست توسط تابع gallop_right انجام می‌شود. این دو تابع انعکاس آئینه‌ای همدیگر هستند.ساختار MergeStateبرای ادغام ساختاری در کد‌هایی که مربوط به الگوریتم تیم‌سورت پیدا می‌شود به اسم MergeState؛ این ساختار اطلاعات مورد نیاز برای توابع ادغام را داراست. اطلاعات دیگری که در این ساختار نگهداری می‌شوند:مقدار min_gallopاندازه‌ی استک Runها: nخود استک Runها: pendingآرایه‌ی موقت ادغام کردن: temparray وسه تابع key_compare و key_richcompare و tuple_elem_compare برای سناریو‌های مختلف مقایسه کردن بین عناصر آرایه.کد این ساختار اینجا قرار دارد.جلوگیری از بازگشتی شدن الگوریتمتوابع بازگشتی وقتی که صدا زده می‌شوند، اطلاعات هر بار صدا زده شدن آنها، در در یک stack ذخیره می‌شوند، اما آقای تیم پیترز این الگوریتم را که ماهیت بازگشتی مانندی دارد را غیر بازگشتی نوشته است و برای اینکار از یک stack مخصوص خودش در سطح کد استفاده می‌کند. هر بار که یک Run پیدا می‌شود و اندازه‌ی آن به minrun و یا بیشتر می‌رسد، اطلاعات آن روی stack گذاشته می‌شود.اگر بخواهیم ساده نگاه کنیم فرض می‌کنیم، خود Run روی استک گذاشته می‌شود اما در واقع فقط آدرس شروع و اندازه‌ی آن روی استک ذخیره می‌شود تا از تکه تکه کردن آرایه و اشغال فضای بیشتر جلوگیری شود.این استک، نقاط شروع و طول هر Run را در خودش ذخیره می‌کند.این یعنی: Run عه iام از آدرس base[i] شروع شده وlen[i] تا ادامه دارد و این عبارت همیشه درست است:برای اینکه اندازه‌ی Runها دقیقا و یا تقریبا با هم برابر بمانند تا الگوریتم‌های ادغام آنها را سریع‌تر ادغام کنند، هر بار که یک Run جدیدی ساخته می‌شود اطلاعات آن روی استک گذاشته می‌شود، دو شرط برای Runهای روی استک چک می‌شوند.اگر روی استک ما Runهای Xو Y و Z وجود داشته باشند، این شروط باید حفظ شوند:شرط دوم بر این دلالت دارد که اندازه‌ی Runها از بالا به پایین به صورت صعودی باشد و شرط اول بر این دلالت دارد که وقتی از بالا به پایین می‌رویم طول Runها حداقل با سرعت دنباله‌ی فیبوناچی رشد کنند.اگر هر کدام از این شروط نقض بشوند، Run عه Y با Run کوچک‌تر از بین X یا Z ادغام می‌شود و شروط دوباره چک می‌شوند و اگر برقرار بودند، الگوریتم به دنبال Run بعدی در آرایه جستجو می‌کند.برای مثال اگر هر کدام از X یا Z که کوچک‌تر باشند، با Y ادغام می‌شوند (که الگوریتم X را ترجیح می‌دهد؛ بخاطر اینکه در کش تازگی دارد.)برای مثال اگر این Runها را داشته باشیم:ران عه Y با X ادغام می‌شود:و یا اگرران Y با Z ادغام می‌شود:که در هر دو مثال شرط دوم نقض می‌شود و الگوریتم تا زمانی که این دو شرط درست شوند، به ادغام کردن ادامه می‌دهد و در نهایت، تنها یک Run روی استک باقی می‌ماند که آرایه‌ی مرتب شده‌ی ماست.تابع merge_collapse مدیریت این شروط را به عهده دارد و انتخاب می‌کند که کدام Runها با هم ادغام شوند و این کار را با تابع merge_at انجام می‌دهد.عمل ادغام تصمیمات مبنی بر اینکه ادغام باید با galloping شود یا نشود را از نتایج توابع galloping اتخاذ و عملیات ادغام با توجه به شرایط را با کمک توابع merge_lo و merge_hi انجام می‌دهد.مروری بر Timsortاگر بخواهیم روی مطالبی که خواندیم مروری داشته باشیم الگوریتم به طول کلی یکبار از سمت چپ شروع به حرکت در آرایه می‌کند، قسمت‌‌هایی که از قبل ترتیبی صعودی یا اکیدا نزولی دارند را شناسایی می‌کند، اگر اندازه‌ی آنها به اندازه‌ی minrun نبود آنها را به صورت مرتب بزرگ‌تر می‌کند تا به minrun برسند و سپس با سیاست‌های خاصی برای ادغام، مانند استفاده از یک آرایه‌ی موقت کوچک، نزدیک نگه داشتن طول Runها برای ادغام و ادغام با استک برای جلوگیری از بازگشتی شدن الگوریتم آنها را با هم ادغام می‌کند.اسلاید‌های ارائه‌ی الگوریتماگه برای ارائه‌ی این الگوریتم به اسلاید نیاز دارید می‌تونید از اسلاید‌های من در اینجا https://github.com/mahdihaghverdi/timsort فایل slides.pdf استفاده کنید.منابع:https://github.com/python/cpython/blob/3.10/Objects/listsort.txthttps://github.com/python/cpython/blob/3.10/Objects/listobject.chttps://en.wikipedia.org/wiki/TimsortFASTEST Sorting Algorithm (Part I)FASTEST Sorting Algorithm (Part II)FASTEST Sorting Algorithm (Part III)FASTEST Sorting Algorithm (Part IV)</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Fri, 26 Jan 2024 14:09:30 +0330</pubDate>
            </item>
                    <item>
                <title>بیاید تا عبارت 4w5d12h50m13s رو tokenize و parse کنیم</title>
                <link>https://virgool.io/@liewpl/tokenizer-parser-in-python-ubzlsvukmdxz</link>
                <description>یکی از دروس تخصصی و خیلی زیبای رشته دانشگاهی مهندسی کامپیوتر درس نظریه‌ زبان‌ها و ماشین‌هاست.در واقع این درس به همراه درس ریاضیات گسسته، دو درس اصلی علوم کامپیوتر هستند، که البته در علوم کامپیوتر با عنوان نظریه محاسبات تدریس می‌شود.هدف درس نظریه محاسبات یا نظریه زبان‌ها اینست که حد و مرز توانایی ماشین‌‌ها برای انجام محاسبات را بفهمیم. در ابتدا با ساده‌ترین زبان‌ها شروع می‌کنیم و در پایان به زبان‌ها بازگشتی می‌رسیم که با ماشین تورینگ تشخیص داده می‌شوند. در نهایت می‌گوییم هر مسئله‌ی محاسبات ریاضی را می‌توان توسط یک زبان مدلسازی کرد. مثلا این مسئله را در نظر بگیرید: آیا یک عدد اول است یا خیر؟ مسئله‌ی اول بودن یک عدد را می‌توانیم به شکل دیگری مطرح کنیم. آیا یک عدد متعلق به مجموعه‌ی اعداد اول است یا خیر؟ حال باید ماشینی طراحی کنیم که زبانی که شامل همه اعداد اول است را شناسایی کند. پس مسئله بررسی اول بودن یک عدد معادل است با طراحی ماشین برای تشخیص اول بودن عددی که به صورت رشته به ماشین داده می‌شود. حال می‌توانیم با استفاده از یک ماشین تورینگ (و کد گذاری اعداد) این کار را انجام دهیم.پس می‌توانیم الگوریتم را بر اساس تشخیص پذیری در ماشین تورینگ تعریف کنیم.همچنین اثبات می‌شود که مسئله‌هایی وجود دارند که برای آنها هیچ الگوریتمی وجود ندارد و یا به عبارت دیگر هیچ ماشین تورینگی برای زبان معادل آنها وجود ندارد. این مسئله‌ها تصمیم ناپذیرند.پس همه‌ی علم محاسبات در مورد پیدا کردن حد و مرز توانایی محاسبات توسط ماشین‌هاست.[3]یکی از منابع این درس (که استاد ما هم همین منبع رو استفاده کردن) این کتابه:Linz, Peter, and Susan H. Rodger. An introduction to formal languages and automata. Jones &amp; Bartlett Learning, 2022 https://books.google.com/books?hl=fa&amp;lr=&amp;id=MV6mEAAAQBAJ&amp;oi=fnd&amp;pg=PP1&amp;dq=introduction+to+formal+languages+and+automata+jones+and+barlet&amp;ots=RN9Tn3zmIB&amp;sig=iiD9CRfAvLlN98RQtzB8FSj80fs#v=onepage&amp;q=introduction%20to%20formal%20languages%20and%20automata%20jones%20and%20barlet&amp;f=false در منطق، ریاضیات، علوم کامپیوتر و زبان‌شناسی، نظریهٔ زبان‌ها به مطالعهٔ زبان‌های صوری و دسته‌بندی آنها می‌پردازد. در نظریهٔ زبان‌ها تنها جنبه‌های نحوی زبان‌ها (یعنی الگوهای ساختاری درونی آنها) تجرید و انتزاع می‌شود و به معنای جملات و ... اهمیتی نمی‌دهیم (مثلاً جملهٔ «رنگ آسمان قرمز است» ممکن است در یک زبان صوری جملهٔ مورد قبولی باشد).یک زبان تشکیل شده از کلماتی‌ست که حروف آن، توکن‌هایی گرفته شده از یک الفبای مشخص هستند که تحت یک سری قانون خاص به اسم گرامر به صورت خوش‌ساخت ساخته شده است.[۱]در علوم نظری رایانه، نظریهٔ اتوماتا (به انگلیسی: Automata theory) یا نظریهٔ ماشین‌ها عبارت است از بررسی ریاضی ماشین‌های محاسبه‌گر انتزاعی و توانایی‌های  آن‌ها برای حل مسایل. به این ماشین‌های انتزاعی اتوماتا گفته می‌شود. این  نظریه بسیار نزدیک به نظریهٔ زبان صوری است. به‌طوری‌که اتوماتا اغلب توسط دستهٔ زبان‌های رسمی قابل تشخیص  دسته‌بندی می‌شوند. اتوماتا نقش اساسی در طراحی کامپایلر و تجزیه کردن  (parsing) ایفا می‌کند. زبان‌هایی که توسط این ماشین‌ها بررسی می‌شوند زبان‌های فرمال هستند.[۲]در یک گروه پرسش و پاسخ پایتونی در تلگرام (PyFarsi@) یکی از اعضا یک سوالی پرسید که دیدم میشه یکمی مباحث نظریه زبان‌ها و ماشین‌ها رو باهاش بررسی کرد و بعدش اون‌ها رو کد کرد. پس بیاید تا سوال رو ببینیم و بعدش راه‌حلش رو هم به صورت تئوری و هم به صورت عملی (کدی) بنویسیم.سلام بچه‌هاببخشید من میخوام از کاربر یک ورودی بگیرم و بعدش با توجه به یک سری اصول اون رو بفهمم و اگه اشتباه بود ارور بدم و اگه نبود اون رو تبدیل به اطلاعات قابل استفاده بکنم. ورودی من اینه:4w13d16h10m14sکه میخوام متوجه بشم که بهم گفته ۴ هفته و ۱۳ روز و ۱۶ ساعت و ۱۰ دقیقه و ۱۴ ثانیه. ترتیب هم برام مهم نیست یعنی میتونه اول ثانیه بگه بعد هفته بگه و... صرفا چیزی که برام مهمه اینه که یک عدد و سپس یه حرف باید بهم بده.نوشتن عبارت منظم (regular expression)اگه دقت بکنید، ما با یک ساختار نظام‌مند طرف هستیم: «عددحرف | عددحرف | عددحرف‌ | ...» که چون نظام‌مند هست میتونیم براش یک زبان و عبارت منظم بنویسیم، سپس برای اون عبارت منظم یک DFA یا NFA بنویسیم، و اون رو تبدیل به کد کنیم. این دقیقا کاری هست که برای طراحی کامپایلر‌ها انجام میدن (البته خییلی پیشرفته‌تر و حرفه‌ای‌تر.)اولین چیزی که نیاز داریم الفبای زبانمونه. الفبای زبان ما از حروف زیر تشکیل شده:۰، ۱، ۲، ...، ۹ و w, d, h, m و s.در واقع در نظریه زبان‌ها ما به تمام الفبامون میگیم یک حرف (letter) و مجموعه‌ی الفبای ما میشه مجموعه سیگما«الفبای زبان ما»به علت اینکه جلوتر ما با اعداد و حروف به صورت جداگانه کار داریم بیاید تا مجموعه‌ی سیگما به صورت اجتماع ۴ تا مجموعه‌ی دیگه بنویسیم:که مجموعه‌‌های اعداد مثبت غیر صفر (positive)، مجموعه‌ی ارقام (digits) و مجموعه‌ی حروف (letters) رو داریم.حالا باید عبارت منظم (regular expression) این زبان رو بنویسیم. اگه نمیدونید عبارات منظم چی هستن یه سر به این لینک بزنید و بیاید حالا کمی عبارتی که بهمون داده شده رو تفسیر کنیم و کم کم عبارت منظمش رو بنویسیم.توی عبارت ما یک الگوی مشخص می‌بینیم: «عددحرف» و کل عبارت ما میشه ۱ یا چند تا از این «عددحرف»ها پس ما اول باید برای «عددحرف» یک  عبارت منظم بنویسیم.اگه دقت کنید میتونیم اینجوری بگیم که قسمت عدد این تیکه، میتونه اعدادِ تک رقمی (از ۱ تا ۹) و یا ۲ رقمی، ۳ رقمی و... باشن، و با صفر هم نمیتونن شروع بشن (یعنی ۰۰۱۳ رو معتبر نمیدونیم) پس میشه چنین چیزی براش نوشت:که عملگر dot در اینجا به معنی concatenation هست. یعنی دو تا حرف رو بهم بچسبونیم. و آوردن اسم مجموعه‌ها یعنی یکی از اعضای اون‌ها.این عبارت نشون میده اولین رقم میتونه از بین اعداد ۱ تا ۹ انتخاب بشه و رقم بعدی میتونه از بین ۰ تا ۹ انتخاب بشه، این رو هم یادمون باشه که چیزی که الزامیه حضور یک رقمه و این یعنی تعداد رقم‌ها باید بزرگ‌تر مساوی یک باشه. خب ما که حضور اولین رقم از مجموعه‌ی p رو تضمین کردیم، پس تعداد رقم‌های بعدش میشن بزرگ‌تر مساوی صفر که این مفهوم رو در عبارات منظم با این نوتِیشن نشونش میدیم:این شد قسمت «عدد» از «عددحرف»مون. قسمت حرفش هم خیلی راحته، بعد از هر عددی، *باید* یکی از حروف مجموعه اِل حاضر باشن که میشه اینجوری نشونش داد:یا برای واضح‌تر نشون دادنش اینجوری:که عملگر pipe میشه یا این یا این یا این، یعنی تنها یکی از اینا اجازه دارن که حضور داشته باشن.این هم قسمت «حرف» از «عددحرف»مونحالا وقشته که این دو رو بهم concat کنیم:اینم شد عبارت منظم «عددحرف» ما. اما کار ما هنوز با عبارت منظم تموم نشده، اگه دقت کنید این عبارت فقط یک دونه از «عددحرف»‌ها تولید میکنه؛ اما چیزی که به ما میدن میتونه بیشتر از یکی هم از این «عددحرف»‌ها داشته باشه که عبارت منظم نهایی ما میشه:عملگر + هم مثل عملگر * هست ولی حضور یک عبارت رو تاکید و تضمین میکنه ولی * میشه صفر یا بیشتر.کشیدن ماشین متناهی (DFA)حالا، برای راحت‌‌تر شدن فهمیدن عبارت منظم، میتونیم از روی r، یک DFA طراحی کنیم.برای مطالعه‌ی DFA میتونید یه سر به این لینک بزنید: https://en.wikipedia.org/wiki/Deterministic_finite_automaton و DFA ما (که از روی عبارت منظممون کشیدمش) میشه:و اما چرا این؟ بیاید تا بررسیش کنیم: اول از همه state شروع هست که همه‌ی automataها اون رو دارن،سپس ورودی ما میتونه از بین عدد ۰، یک حرف (مجموعه L) و یکی از اعداد ۱ تا ۹ (مجموعه p) باشهدر ابتدا، ۰ و یک حرف قابل قبول نیستن و ما وارد یک تله میشیم که هررر ورودی دیگه‌ای بهش بدیم فقط به خودش برمیگرده. این یک تکنیک برای نوشتن DFAهاست که بگیم دیگه از این به بعد ورودی کاملا غلطهحالا اگه ورودی از مجموعه‌ی p بود وارد digits میشیم، الان یک رقم عدد داریم که غیر صفره -&gt; یعنی یکی شرط وجود عدد در عبارت «عددحرف» رو رعایت کردیم. و یه حلقه روی این state داریم از بین اعدا ۰ تا ۹ میتونه هیچ و یا هرر چی دلش خواست ورودی دریافت کنهبه محض اینکه یک حرف دریافت کردیم وارد success میشیم. این یعنی یک ترکیب «عددحرف» دریافت کردیم.حالا باز دوباره مثل state عه شروع ما میتونیم از بین ۰ و حرف و اعداد بین ‍۱ تا ۹ ورودی دریافت کنیم که باز هم مثل state عه شروع فقط میتونیم از اعداد داخل مجموعه‌ی p چیزی رو قبول کنیم و در غیر این صورت باید به تله بریم.این هم ماشین متناهی این سوال. حالا باید بریم و کدش رو بنویسیم :)بررسی کد‌های tokenizerاول از همه بیاید یک دیکشنری از حروفی که توی الفبامون هستن و کلمه‌ی نظیرشون بسازیم:سپس برای کار با توکن‌های تولید شده و همچنین type annotation یک کلاس این چنینی می‌نویسیم:اما برسیم به tokenizer 😁تابع tokenizeاول کد تابع رو ببینیم یبار و بعدش تیکه به تیکه اون رو بررسی می‌کنیم:اِستیت startاگر به DFAمون نگاه کنیم در state شروع، یک دوراهی داریم:اینکه یک عدد از بین مجموعه‌ی اعداد غیر صفر بگیرهیا اینکه ۰ یا یک حرف دریافت کنهمورد دوم رو توی این خطوط هندل کردیم:که خروجی‌هاشون:واستیت digitsفرض کنیم از state عه start با دریافت یک عدد از بین مجموعه‌ی p با موفقیت عبور کردیم به state عه digits رسیدیم. حالا می‌تونیم هر چقدر که بخوایم عدد از ورودی دریافت کنیم، که با این تیکه کد اون رو پیاده‌سازی کردیم:که واسه‌ی توضیح واضح‌ترش یه مثال رو توی دیباگر ببینیم:اگر برای مثال ورودی ما فقط عدد باشه، DFA ما وقتی که تمام رقم‌ها رو دریافت کرد، همونجا توی state عه digits میمونه و دیگه تکون نمیخوره که نشونه اشتباه بودن ورودیه.اما توی کد چی کار کردیم، من اومدم و این تابع رو با ورودی 143 صدا زدم. این حلقه دونه دونه کاراکتر از ورودی میگیره و چک میکنه آیا عدد هستن یا خیر، اگه بودن اون‌ها رو به digits اضافه میکنه و شمارنده‌ی indexها رو یکی زیاد میکنه.مثل الان، ما هیچ حرفی بعد از این اعداد نداریم و وقتی می‌خوایم به ایندکس ۳ دسترسی پیدا کنیم خطای IndexError میگیریم و یک SyntaxError رِیز میکنیم و میگیم:اما اگه بعد از اعداد یک حرفی بود:ما حرف رو میگیریم و توی letter ذخیره می‌کنیم و برای وارد شدن به state عه success آماده میشیم.حالا وقت اینه که چک کنیم حرفی که دریافت کردیم، از بین حروف الفبامون هست یا خیر:که اگه اون حرف از بین حروف مجاز نبود:استیت successحالا که هم ارقام را داریم و هم یک حرف درست، وقتشه که توکنمون رو درست کنیم و تابع رو برای ادامه‌ی رشته‌مون صدا بزنیم تا این روندی که توی استیت‌های بالاتر گفتیم برای کل رشته‌مون تکرار بشه:خط ۶۱ کارش اینه:ببینید ما تا الان تا index عه iام رشته‌مون رو خوندیم و اون رو tokenize کردیم، حالا میخوایم که از index بعدش به بعد رو به تابع‌مون پاس بدیم تا ترکیب «عددحرف» بعدی رو برامون پیدا کنه، پس ما رشته رو slice میکنیم و از اون ایندکس i به بعد رو جدا و به تابع‌مون پاس می‌دیم.وقتی هم که کل رشته‌مون رو گذر کردیم می‌رسیم، این اسلایس کردن برای ما یک رشته خالی تولید میکنه که وقتی پاسش بدیم به تابع، شرطِ base case ما:اجرا میشه و یک لیست از Tokenها در نهایت بازگردانده میشه.بررسی کد‌های parserبعد از نوشتن tokenizer ما باید توکن‌های تولید شده رو parse کنیم و معناشون رو متوجه بشیم. اول از همه کد پارسر این مسئله رو ببینیم:این ورودی رو در نظر بگیرید:tokenizer(&amp;quot2w1d2d3d5s4d7h&amp;quot)ملاحظه می‌شود که 1d و 2d و 3d و 4d همگیشان عبارت‌های «عددحرفی‌» هستند که راجع به روز صحبت می‌کنند. ما در تابع parse اومدیم و یک دیکشنری از کلید‌ها (که days و weeks و...) هستند درست می‌کنیم و مقدار این کلید‌ها میشن اون اعدادی که توی توکن‌ها دخیره هستن.علی که در اولین خط‌های این فایل این دیکشنری رو ساختیم:و این مقادیر رو به عنوان valueهای این کلید‌ها انتخاب کردیم اینه که signature عه تایپ timedelta اینجوریه:و با آنپک کردن این دیکشنری براحتی میتونیم این تایپ رو instantiate کنیم و اون رو برگردونیم :)نمونه‌هایی از خروجی‌های این کد:تمامی عکس‌ها و کد‌هایی که در این مقاله استفاده شدن در این ریپازیتوری: https://github.com/mahdihaghverdi/timetp قابل دسترسی هستن.نوشتنی‌ها و DFA در پوشه‌ی docs قرار دارند. کد‌های اصلی در timetp.py و تست‌هاش در tests.pyبرای اجرا کردنش هم میتونید ریپازیتوری رو فورک کنید و سپس در پوشه‌ای که پوشه‌ی ریپازیتوری هست، با این دستور help اون رو ببینید:$ python -m timetp helpاین هم مقاله‌ی نوشتن یک tokenizer و یک parser کوچیک برای یک عبارت منظم :)[۱]: https://en.wikipedia.org/wiki/Formal_language[۲]: https://en.wikipedia.org/wiki/Automata_theory[۳]: از کلام دکتر آرش شفیعی، عضو هیئت علمی دانشگاه اصفهان (http://fce.ui.ac.ir/~a.shafiei)</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Sun, 17 Dec 2023 16:09:01 +0330</pubDate>
            </item>
                    <item>
                <title>تازه‌‌های پایتون ۳.۱۲</title>
                <link>https://virgool.io/codenevis/python-3-12-whats-new-vpq99njtytc6</link>
                <description>همین امروز فرداست که پایتون ۳.۱۲، آخرین ورژن پایتون release بشه (اطلاعات کامل زمان‌بندی این ریلیس رو اینجا بخونید) بیاید ببینیم این ورژن نسبت به ورژن ۳.۱۱ که پارسال همین موقع‌ها ریلیس شد داشته :-)در این مقاله می‌‌خوانیم:خلاصه‌ای از این ریلیسسینتکس جدیدیک گرامر جدیدپیشرفت‌های مفسراضافه شدن Buffer Protocol به پایتونComprehension Inliningبهبود یافتن Error Messageهاپیشرفت‌هایی در سیستم typing پایتوندیگر بهبود‌هابهبود در stdlibبهینه‌سازی‌هاخلاصه‌ای از این ریلیسپایتون ۳.۱۲ آخرین نسخه‌ی پایدار منتشر شده‌ است. در این نسخه ما ترکیبی از تغییراتی در خود زبان و در stdlib داریم. تغییرات stdlib تمرکز بیشتری روی پاک کردن موارد deprecate شده، صحیح‌تر کار کردن و کارایی دارن. ماژول distutils از stdlib حذف شده و پشتیبانی از filesystem در ماژول‌های pathlib و os خیلی پیشرفت کردن، به علاوه چندین ماژول هم بهبود‌های خیلی خوب در performance داشتن.در تغییراتی که در خود زبان مشاهده می‌کنیم، کارایی زبان بالاتر رفته، بسیاری از محدودیت‌های f stringها حذف شده و پیشنهادات ...Did you mean خیلی بیشتر و بهتر شدند. یک syntax جدید برای معرفی generic types و type aliases معرفی شده.این مقاله قرار نیست توضیحات دقیق و کاملی در مورد همه‌ی تغییرات بده، برای بررسی خیلی دقیق و ریز و همچنین علت تغییرات میتونید به PEPهای این تغییرات و Library Reference و همچنین Language Reference مراجعه کنید.سینتکس جدیدسینتکس جدید برای Generic Classes و Type Aliasesسینتکسی که در PEP 484 برای Generic Classes و Generic Functions معرفی شد، یه کمی خیلی verbost و البته زشت ?? بود اما با PEP 695 بعد ۹ سال یک سینتکس جدید و بسیار زیبا براشون زبان معرفی شده.قبل از این پپ Generic Classes اینجوری معرفی می‌شدن:که خداییش خیلی زشتن ??اما الان چنین سینتکس زیبایی رو داریم:برای توابع هم قبلا از این سینتکس زشتا استفاده میشد:اما الان:بسیار خلاصه، زیبا و البته شبیه به زبان‌هایی که سال‌های سال جنریک و سینتکس خوبی براش داشتن به این جدول نگاه کنید:و خوب اگه دقت کنیم می‌بینیم که کمی از اسکالا و گو و سوئیفت اسکی رفتیم ?سینتکس جدید برای TypeAliasesبه علاوه‌ی این سینتکس جدید، یه سینتکس جدید دیگه هم برای تعریف‌ TypeAliasها معرفی شده. قبلنا برای تعریف یک TypeAlias چنین کدی می‌نوشتیم:اما حالا:برای این PEP تحقیق و بحث بسیاری شده و Specification و Implementation عه بلند و بالایی داره:خیلی زیاده نه؟ مال Generatorها رو دیدید ?؟برای توضیحات بیشتر و عمق ماجرا یه سر به PEP 695 بزنید.یک گرامر جدیددر این ورژن f stringها بالاخره پدر مادردار شدن و محدودیت‌های گذشته‌شون رو پشت‌سر گذاشتن و از نو در زبان تعریف شدن.ویژگی f stringها ابتدا در PEP 498 توسط آقای Eric V. Smith در سال ۲۰۱۵ و پایتون ۳.۶ معرفی شدند و سینتکس خیلی زیبایی رو برای Literal String Interpolation به زبان اضافه کردن، اما بعد از ۸ سال core devها اومدن گرامری که برای توصیف‌ اونها نوشته شده بود رو بهتر کردن که راحتی و انعطاف‌پذیری اونها رو برای ما end userها و library developerها بیشتر کردن و از اون طرف هم زحمت نگهداری کد‌هایی که برای پارس کردن f stringها بود رو خیلی کم کردن. بیاید تا کمی از محدودیت‌های f stringها رو ببینیم:نمیتونستیم از یک quote character برای کل استرینگ و قسمت f string عش استفاده کنیم:که بجاش باید این کار رو می‌کردیم:اما الان:یا مثلا برای f stringهای تو در تو:اما الان:از کامنت‌ها توی multi-line f fstring‌ها نمیتونستیم استفاده کنیم:اما الان:از backslash داخل {} نمیتونستیم استفاده کنیم:اما الان:اما با تلاش‌های بسیاری که برای نسل جدید f stringها شده ما:با تغییراتی که روی نحوه‌ی lex کردن f stringها انجام دادن، الان دیگه مستقیما میتونن با PEG Parserعی که از ورژن ۳.۹ جایگزین (1)LL پارسر قدیمی پایتون شده، اونها رو parse کنن؛ که اگه گفتید خوبیش چیه؟ حالا میتونن برای گزارش اشتباهاتی که توی  f stringها نوشتیم گزارش خیلی دقیق‌تری بدن، تا قبل از پایتون ۳.۱۲:اما الان:برای مطالعه‌ی بیشتر میتونید یه سری به PEP 701 بزنید.پیشرفت‌هایی مفسرPer-Interpreter GILیکی از فیچر‌هایی که زبان پایتون از نسخه‌ی ۱.۵ (سال ۱۹۹۷) داشته این بوده که توی یک process میتونستیم چند تا مفسر رو ران کنیم، ولی خب مضراتش خیلی بیشتر از مزیت‌هاش بوده، اما بعد از ۲۶ سال یه nerd اومده و خیلی خوب اون رو برای پایتون نوشته: A Per-Interpreter GIL برای کامل متوجه شدن این ویژگی PEP 684 رو بخونید. اما به طور خلاصه:پپ شماره‌ی ۶۸۴ کانسپتی روی در سطح C API عه پایتون معرفی کرده که میتونیم در یک process چندین مفسر که هر کدوم GIL خودشون رو دارن ران کنیم، که باعث میشه که بتونیم از یک CPU عه multi-core نهایت استفاده رو ببریم. اگه میخواید از این فیچر در سطح پایتون استفاده کنید باید تا ورژن ۳.۱۳ پایتون صبر کنید ?Low impact monitoring for CPythonاگه بخوایم توی یک جمله از آقای دکتر Mark Shannon راجع به چیزی که نوشتن بشنویم: C++ and Java developers expect to be able to run a program at full speed (or very close to it) under a debugger. Python developers should expect that too.در واقع وقتی کد پایتون رو با یک profiler و یا یک debugger ران میکنیم به طور معمول سرعت کد ما با یک مرتبه‌ی خییلی عظیمی (order of magnitude) کاهش پیدا میکنه! اما اقای مارک شنون کدطلا اومدن یک API برای به اصطلاح خودشون low impact monitoring واسه پایتون نوشتن که از این ریلیس به بعد از sys.monitoring قابل دسترسی خواهند بود. میزان low impact بودن چیزی هم که ارائه میدن: اطلاعات کامل این فیچر هم میتونید از PEP 669 دریافت کنید.اضافه شدن Buffer Protocol به پایتونبرای اینکه خیلی خوب این ویژگی رو درک کنیم، باید اول یکمی مقدمه بچینیم و یه سری چیز رو با هم تست کنیم  و خوبیاش رو بشمریم و سپس بگیم ایول حالا توی سطح پایتون هم اینو داریم.تایپ سیستم پایتون برای کار کردن ماها با binary data دو تا تایپ built-in برامون داره: bytes and bytearrays.تعریف خود داکیومنتیشن پایتون برای Bytes:که خیلی خلاصه شما میتونید دقیقا مثل یک str بهش نگاه کنید که فقط باینری عه! دیدید توی زبان سی ما میایم از تایپ عه char استفاده میکنیم، بعد مثلا برای حرف A عدد ۶۵ جاش ذخیره میشه؟ این هم دقیقا همینه:اما این تایپ bytes یک آبجکت immutable هست و mutable counterpartشون تایپ bytearray هست:توضیح کامل چرایی وجود این تایپ‌ها و چه قابلیت‌هایی دارن، توی این مقاله اصلا نمیگنجه! اگه وقت کردم ایشالا یه مقاله جدا برای بایت‌ها می‌نویستمبرگردیم سر اینکه چرا اصلا داریم اینا توضیح میدیم؛ استفاده از این تایپ‌ها خصوصا هنگام ذخیره‌سازی و کار کردن با دیتا‌‌هایی که ما مثلا باز می‌کنیم (یه عکس یا یه فایل موسیقی مثلا) استفاده میشن، چون بالاخره این فایل‌های موسیقی عکس یه سری بایت هستن که به حالت خاصی انکود شدن، توی پایتون هم ما بهشون به صورت باینری دسترسی داریم.حالا می‌رسیم به اصل ماجراوقتی داریم با این فایل‌ها کار میکنیم، خصوصا وقتی که به قسمت‌هایی ازشون نیاز داریم راه‌حل ساده اینه که اونا رو (چون sequence type  هستن و sequence typeها از sliceها پشتیبانی میکنن) اسلایس اسلایس کنیم. برای مثال بیاید یه bytes خییییلی گنده درست کنیم:یک میلیارد x کنار هم ?? ۹۵۳ فاکینگ مگابایت مموری اشغال کرده! بنظرتون اگه این آبجکت رو اسلایس اسلایس کنیم، چی میشه؟ بیاید تا دو قسمتش کنیم و ذخیره‌ش کنیم:که منطقیه! چرا؟ چون وقتی آبجکتی رو اسلایس می‌کنیم، پایتون یک کپی از روی اون می‌سازه! اما خب دردسازه ?? همین الان همین کنسول حدودا دو گیگ مموری گرفته!! دو تا 953 مگابایت! و این هر چقدر که شما بیشتر اسلایس انجام بدید، ادامه پیدا میکنه! که برای سایز‌ها کوچیک خیلی مسئله‌ی مهمی نیست ولی برای چیزای حجیم چرا!آیا پایتون براش راه‌حل نداره؟ البته که داره ? پایتون راه‌حلی ارائه داده که شما به طور کاملا مستقیم به buffer (در واقع لایه‌ای از مکانی که اون آبجکت‌توی مموری ذخیره شده) دسترسی داشته باشید و بدون کپی‌ کردن‌های بیخودی، از اونجا چیزی بخونید یا بنویسید،امایه امای بزرگ اینجا هست، اون آبجکت باید از Buffer Protocol پشتبانی کنه، طبق تعریف بسیار دقیق و زیبایی داک پایتون، بافر پروتوکل اینه:یه مثال  یگه بزنم تا متوجه بشید این کپی کردن‌ها کجا ممکنه دردسرساز بشن، فرضضضض کنید یه فایل باینری خیلی بلندی داریم (دقیقا مثل مثالمون یک میلیارد x پشت سر هم) و میخوایم تیکه‌های منتخب و زیادی ازش رو توی یه فایل دیگه بنویسیم، یه مثال خیلی کوچیک:اینکه بیایم هی تیکه تیکه اسلایسش کنیم و اون تیکه اسلاید رو بدیم به تابع write مموری‌مون پر پر پر میشه و پراسس kill میشه؛ اما حالا که داریم از باینری تایپ‌ها استفاده می‌کنیم و از قضا اینا از بافر پروتوکل پشتیبانی میکنن می‌تونیم اون‌ها بدون کپی شدن اسلایس کنیم ? اینجاست با یک تایپ جدید به اسم memoryview آشنا میشیم:توضیح کامل این تایپ هم مثل تایپ‌های قبلی هم توی این مقاله نمی‌گنجه اما تبعات استفاده ازش چرا ?بیاید تا با استفاده از memoryview اون آبجکت خیلی گنده‌مون رو اسلایس کنیم ببینیم چی میشه؛ ابتدا یک memoryview ازش می‌سازیم:چه سایزی ? صفر!حالا بیاید تا اسلایس کنیم:و باز هم سایز صفر، این دقیقا به این دلیله که ما با first_half دقیقا به اون تکه از مموری دستری داریم که اون آبجکت توش هست و هیچ کپی‌ای انجام ندادیم. و میتونیم براحتی ازش هر جایی که بخوایم استفاده کنیم و باز هم اسلایسش کنیم و هیچ memory overhead عی توی برنامه‌مون نداشته باشیم.اما چیزی که در پایتون ۳.۱۲ بوسیله‌ی PEP 688 اضافه شده، اینه که همین buffer protocol رو به سطح پایتون آورده و شما می‌تونید custom buffer classes بنویسید و ازشون نهایت استفاده رو ببرید:طبق این PEP دو تا داندر متد جدید به پایتون اضافه شده: __buffer__ و __release_buffer__ که داندر بافر باید یک memoryview برگردونه و داندر ریلیس بافر اون رو ریلیس کنه!برای توضیحات کامل‌تر PEP 688 رو بخونید.Comprehension inliningکامپریهنشن‌ها یکی از جذاب‌ترین سینتکس‌های معرفی شده (و البته اسکی رفته از notationهای ریاضی) هستن که طرفداران زیادی هم دارن! طوری که کامپریهنشن‌ها تا قبل از پایتون ۳.۱۲ کار می‌کردن این بود که هر کامپریهنشن تبدیل به یک تابع میشد و اون تابع دقیقا مثل یک تابع معمولی ساخته، کامپایل و صدا زده میشد:ببینید، اولین بایت‌کدی که اجرا میشه (هنگام صدا زده شدن تابع) اینه که یک کد آبجکت لود بشه!! کد آبجکت کدی که داخل اون listcomp نوشته شده! بعدش ببینید! دو تا بایت‌کد توی ۴ و ۱۰! MAKE_FUNCTION و CALL_FUNCTION و این یعنی پایتون از اون بایت‌کد یک تابع می‌سازه و سپس صداش میزنه! و این یعنی عینا مثل توابع باهاشون رفتار میشه، یعنی یک frame object براشون تشکیل میشه، توی tracebackها نشون داده میشن و بعد از استفاده شدن اون تابع درست شده، دور انداخته میشه! و این یعنی هر بار تابع f رو صدا بزنید، یک تابع دیگه درونش ساخته میشه!اما خب این روند دیگه توی پایتون ۳.۱۲ وجود نداره و comprehensionها به اصطلاح inline میشن و دیگه تابعی براشون درست نمیشه! و فریمی هم نخواهند داشت:و در استک‌تریس هم نیستن:برای اطلاعات کامل‌تر و جزئیات بیشتر PEP 709 رو بخونید.بهبود یافتن Error Messageهاماژول‌هایی از stdlib که اسمشون استفاده شده ولی import نشدن:اکسپشن NameError که در instance methodها هنگام استفاده از attributeهای اون instance رِیز شدن:سینتکس ارور وقتی که برنامه‌نویس نوشته import a.y.z from b.y.zرِیز شدن ImportError هنگام ایمپورت‌ کردن چیزی از جایی حالا بر اساس اسامی‌ای که در اون ماژول وجود دارن پیشنهاداتی بهمون ارائه میدن:پیشرفت‌هایی در سیستم typing پایتوناستفاده از TypedDict برای annotate کردن kwargs**حالا ما می‌تونیم type annotation دقیق‌تری برای آنبپک کردن kwargs** داشته باشیم:(سباستین رامیرز نویسنده‌ی FastAPI: ???)برای کسب اطلاعات بیشتر به PEP 692 مراجعه کنید.Override Decorator for Static Typingیه دکوریتور بیخودی هم نوشتن که نه تنها کد رو زشت میکنه بلکه که میخوام به کسایی که این PEP رو قبول کردن تا اومد پایتون ۳.۱۳ یعنی تقریبا یک سال روزی ۱۰۰ مرتبه فحش بدم!!!کلا به من چه هم که این زبونا این رو دارن:ولی بهرحال آورده شده، و این جونور زشت اینجوریه:و البته یکی از دلایلی هم که براش آوردن اینه که اگه یه متدی از یک کلاسی رو شما override کرده باشید و بعد توی کلاس Parent اسمش رو عوض کنید، کدتون ران میشه، و فقط وقتی به هنگام استفاده از متدی که توی کلاس فرزند هست میرسه اون متد با اسم قبلی (که قبلا اون متد رو اورراید کرده بود) رو اجرا میکنه که ممکنه تولید باگ کنه. فرض کنید چنین کدی داریم:حالا اسم foo داخل کلاس Parent رو عوض میکنیم، چیزی که داریم:اما پپ میگه اگه با override دکوریت‌اش کرده بوده باشیم type checker بهش گیر خواهد داد.ولی بهرحال کلی کد زشت به پایتون اضافه کردن ?? می‌تونید راجع بهش در PEP 698 بخونید.دیگر بهبود‌هااز حالا می‌تونیم توی comprehensionها از =: استفاده کنیم: [(b := 1) for a, b.prop in some_iter]آبجکت‌های slice حالا hashable شدند و میتوان اون‌ها رو توی setها و به عنوان کلید در دیکشنری‌ها استفاده کرد. (PEP 572)تابع sum حالا از الگوریتم Neumaier summation برای محاسبه دقیق‌تر استفاده می‌کنه.بهبود در stdlibماژول array تایپ array.array از این ورژن از subscripting پشتیبانی میکنهماژول asyncioپرفورمنس نوشتن به socketها با جلوگیری از کپی گرفتن‌های نالازم بسیار بیشتر شدهدو تابع جدید asyncio.eaget_task_factory و asyncio.create_eager_task_factory اضافه شدند که در مواردی در حدود ۲ تا ۵ برابر سریع‌تر تسک‌ها رو اجرا کنند (gh_97696, gh_102853, gh_104140, gh_104138)تابع asyncio.create_task حالا به زبان C نوشته شده ۴ تا ۶ برابر افزایش سرعت داره.ماژول itertoolsاز الان ما تابع itertools.batched رو در stdlib داریم :)ماژول mathتابع math.sumprod برای محاسبه‌ی جمع یک سری ضرب اضافه شده.ماژول pathlibاز الان میتونیم کلاس‌های pathlib.PurePath و pathlib.Path و کلاس‌های مخصوص Posix و Windows رو ساب‌کلاس کنیم.متد pathlib.Path.walk به این ماژول اضافه شده.ماژول sqlite3از حالا این ماژول یک command line interface هم داره که میتونیم اینجوری ازش استفاده کنیم:ماژول unittestفلگ جدید durations-- به اینترفیس این ماژول اضافه شده:ماژول uuidاین ماژول هم مثل ماژول sqlite3 از الان یه command line interface داره:بهینه‌سازی‌هاتوابعی که regular expression substitution انجام میدادن (functions re.sub() and re.subn() and corresponding re.Pattern methods) ۲ تا ۳ برابر سریع‌تر شدند.ساخته شدن instanceهای asyncio.Task سریع‌تر شده.توابع ()tokenize.tokenize و ()tokenize.generate_tokens تا ۶۴٪ سریع‌تر شدند.صدا زده شدن ()super و لود کردن attributeها سریع‌تر شدند.طبق این صفحه: https://docs.python.org/3.12/whatsnew/changelog.html حدود ۱۵۳۲ تا issue برای این ریلیس بسته شدند که اولین اون‌ها (از نظر زمان ایجاد شدن): https://github.com/python/cpython/issues/39615 هست که تاریخ باز شدنش سال ۲۰۰۳ هست و آخرین اون‌ها: https://github.com/python/cpython/issues/110045 که ۵ روز پیش باز شده و یک روز بعد بسته شده :))پایتون هر سال داره خیلی پیشرفت میکنه، ما به عنوان پایتون دولوپر‌ها باید همیشه اخبار پایتون رو دنبال کنیم و ببینیم چه چیز‌های جدید توی هر ریلیس بهش اضافه تا بتونیم کد‌های بهتری رو بنویسیم.</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Tue, 03 Oct 2023 20:13:30 +0330</pubDate>
            </item>
                    <item>
                <title>بررسی عمیق آبجکت‌ها و تایپ‌ها در C layer مفسر CPython</title>
                <link>https://virgool.io/@liewpl/cpython-objs-types-c-layer-deep-dive-m5fjelhzrzny</link>
                <description>بسیار شنیدیم که همه‌چیز در پایتون آبجکت است. با اینکه این جمله درسته ولی خب یه سوال پیش میاد! زبان C که پایتون نیست، پایتون هم که C نیست پس چجوری با C چیزی نوشتن که توی پایتون ما به همه‌چیز میگیم آبجکت! حتی اگر source code پایتون رو هم دیده باشید با چنین خطوطی مواجه می‌شید:همونطور که شاید حدس زده باشید این‌ها توابعی برای تایپ datetime هستند. return type‌های همه‌شون یه پوینتر از تایپ PyObject هست، تایپ بعضی آرگومان‌هاشون همین‌طور!!این‌ها هم C API برای تایپ لیست در پایتون!و این هم جزئی از مهم‌ترین فایل و قدیمی‌ترین فایل‌های source code عه CPython، که به قول خودشون این یک ارث‌بری دست‌ساز برای خودمونه D:توی این مقاله بررسی می‌کنیم:ساختاری به نام PyObjectساختاری برای typeهاتایپ tupleساختاری به نام PyObjectهمونطور که بالاتر هم نشون دادم، یه نگاه گذرا به سورس کد CPython بهتون نشون میده که چه بسیار از struct عه PyObject استفاده میشه، در واقع وقتی مفسر داره کد ما رو توی interpreter loop (حلقه‌ی خیلی بزرگی که دونه دونه بایت‌کد‌‌های مارو اجرا میکنه) اجرا میکنه، همه‌ی مقادیر رو توی evaluation stack به عنوان PyObject در نظر میگیره. اگه بخوایم خیلی بهتر بهش اشاره کنیم میتونیم بگیم این PyObject سوپرکلاس تمامی آبجکت‌های پایتونه (همونطوری که توی پایتون میگیم کلاس object سوپرکلاس همه‌ی کلاس‌های ماست و همه ازش ارث می‌برن.)‌البته مقادیر در پایتون هیچ‌وقت به عنوان PyObject تعریف (declare) نمیشن بلکه همیشه یک pointer به مقادیر *میتونه* به PyObject اصطلاحا cast بشه.سخنی در مورد C structsوقتی میگیم: مقادیر در پایتون هیچ‌وقت به عنوان PyObject تعریف (declare) نمیشن بلکه همیشه یک pointer به مقادیر *میتونه* به PyObject اصطلاحا cast بشه. داریم به یکی از implemention detailهای زبان C و اینکه این زبان مکان دیتا در مموری رو برای خودش تفسیر می‌کنه، اشاره می‌کنیم.برای تعریف تمامی آبجکت‌های پایتون از C structها استفاده شده. C structها چیزی جز *گروهی از بایت‌ها* در مموری نیستن! که به ما اجازه میدن هرطوری که ما میخوایم بهشون اشاره کنیم، این یعنی چی؟ یعنی فرض کنید یه struct عه test داریم که ۵ مقدار short داخل خودش داره:که هر مقدار short دو بایت هست و در کل این struct ده بایت از مموری رو اشغال میکنه. حال در C یه رفرنس به ده بایت در مموری رو میتونیم ما به test کَست کنیم و *فرض کنیم* که این ده بایت رو یک struct عه test ساخته (که البته که میتونه نساخته باشه.) این به این معنی هست که وقتی ما n بایت دیتا که داره یک آبجکت پایتونی رو نشون میده داشته باشیم و این n از سایز PyObject بزرگ‌تر باشه، میتونیم اون n بایت ابتداییش رو به عنوان PyObject در نظر بگیریم و به اون cast کنیم.این هم PyObject:اون ماکرو عه PyObject_HEAD_EXTRA_ اینه:کار ماکرو اینه که اون PyObject_HEAD_EXTRA_ رو توی سورس‌کد، با چیزایی که جلوش تعریف شده جایگزین کنه، که میشه:که دو تا فیلد ob_next_ و ob_prev_ رو تعریف میکنه که به آبجکت ساخته شده‌ی قبلی و بعدی اشاره میکنن که شبیه به یک doubly linked list میشه و یعنی همممه‌ی آبجکت‌های پایتون مثل زنجیر بهم وصل میشن D:فیلدِ ob_refcnt که یه جور عدده برای memory management اسفاده میشه و فیلد مهم ob_type هم یک پوینتر به یک ساختار دیگه‌ست که type اون آبجکت رو مشخص میکنه. این پوینتر مشخص میکنه که:این دیتا چیه! (what the data represents)چه جور دیتایی داخلش هست وچه کار‌هایی (رفتار‌‌های آبجکت) میشه روی این آبجکت‌ انجام داد.که توی پایتون میشه اینجوری بهش نگاه کرد:این اسم name داره به یک آبجکت string اشاره میکنه که تایپ اون آبجکت str هست.سوال یک میلیون دلاری ?? این چطور امکان‌پذیره؟!!سخنی در مورد reference countingمفسر CPython از reference counting برای memory management استفاده میکنه؛ این یک روش ساده‌ست که وقتی یک *اسم* جدید به یک آبجکت bound میشه (مثل مثال بالا برای name و اون &#x27;obj&#x27;) reference count عه اون آبجکت زیاد میشه و برعکس، وقتی یک رفرنس از یک آبجکت کم میشه (برای مثال استفاده از del) reference count اون هم کم میشه. و وقتی reference count یک آبجکت صفر بشه، اون آبجکت توسط VM اصطلاحا deallocate میشه.خیلی خوب، بالاتر صحبت از این کردیم که همه‌ی مقادیر رو میشه به PyObject کست کرد، و صحبت از اون implementation detail هم کردیم که در C structها وجود داره، اما میشه اون رو، توی source code هم ببینیم؟چه چیزی توی همه‌شون مشترکه؟ بلی دقیقا این ماکرو:این ماکرو یک ob_base از نوع PyObject برای اون‌ها میگذاره که همین باعث میشه که بشه (طبق همون توضیحات بالا راجع به C structها،) اون‌ها رو به PyObject کست کرد.تایپ PyVarObject خواهر PyObjectاول یه سر سورس کد آبجکت لیست رو ببینیم:خبری از PyObject_HEAD نیست و یک ماکرو دیگه جاش هست: PyObject_VAR_HEAD.این ماکرو:که یک ob_base از PyVarObject برای آبجکت میگذاره، اما خب این PyVarObject که به عنوان خواهر PyObject میشناسیمش چیه؟اینه:این struct برای آبجکت‌هایی مثل list استفاده میشه که به قول انگلیسیا:they have some *notion* of lengthو خب تعداد آیتم‌های درونی اون‌ آبجکت رو نگهداری می‌کنن؛ و چنین میشه تابع len در پایتون همیشه از (1)O برخوردار باشه ? چون صرفا باید یک مقدار رو بخونه و برگردونه.ساختاری برای typeهاتایپ‌ها در CPython توسط struct عه typeobject_ تعریف می‌شوند. این C struct در واقع base تمامی تایپ‌های مورد استفاده در CPython هست و فیلد‌های زیادی که داره که اکثراً پوینتر‌هایی به C functionهای دیگه هستن که کارایی (functionality) عه اون تایپ رو پیاده‌سازی (implement) می‌کنند.که اینه:تمامی این فیلد‌ها و مورد استفاده‌شون به طور کامل در اینجا: https://docs.python.org/3.11/c-api/typeobj.html راجع بهشون صحبت شده.اما بیاید تا با یک مثال این ساختار رو بررسی کنیم.تایپ tuple:اول از همه آبجکت تاپل:این هم تایپ تاپل:ماکروی ابتدای این struct:یادتونه که گفتیم همه‌ی آبجکتا رو میتونیم به PyObject کست کنیم؟ و یادتونه که خواهر PyObject که PyVarObject رو معرفی کردیم که خود این PyVarObject هم میشد به PyObject کست کرد؟ و باز هم یادتونه که توی PyObject چه فیلد‌هایی رو داشتیم؟یک فیلد که ob_refcnt بود و یک فیلد‌ هم ob_type، و ما دقیقا داریم با این ماکرو اون ob_type این struct رو مقدار میدیم؟ اونم چه مقداری! جواب سوال میلیون دلاری بالا: بله، تایپ عه تایپ D:این باعث میشه که خروجی زیر رو ما ببینیم:تایپ عه type همون متاکلاس پیشفرض تمامی کلاس‌های پایتونه که اگه به سورس کدش نگاه کنیم: می‌بینیم که تایپ عه تایپ، تایپ هست :) و این هم اثبات این ماجرا:حال اینکه چرا از PyVarObject_HEAD_INIT و آوردن فیلد ob_size استفاده شده رو جلوتر راجع بهش توضیح میدم.فیلد tp_name:این فیلد برای نام‌گذاری این تایپ استفاده میشه که توی مثال ما tuple هست. در واقع __name__ این فیلد رو میخونه و به ما برمی‌گردونه: این فیلد وقتی که کلاس در یک ماژول یا پکیج خاصی هم باشه، اسم اون ماژول و پکیج رو با استفاده از نقطه توی اسمش مشخص میکنه:فیلد‌های tp_basicsize و tp_itemsize:که در داکیومنتیشن:در واقع پایتون از این فیلد‌ها استفاده میکنه تا بدونه موقع ساختن instance از این آبجکت و تایپ، چقدر باید از مموری رو باید اشغال کنه، فیلد tp_basicsize همونطور که اسمش مشخصه برای یک حالت بیسیک و پایه‌ای از آبجکت هست‌ (مثلا تو مثال ما یه تاپل خالی.)برای tp_itemsize دو حالت پیش میاد، طبق حرف documentation برای آبجکت‌هایی که variable-size هستن‌ (مثل مثال ما) این فیلد باید مقداری که اونا نگه میدارن رو ذخیره کنه (که همه پوینتر‌هایی از PyObject هستند و سایزشون توی سیستم‌های ۳۲ بیت ۴ بایت و ۶۴ بیت ۸ بایت هست) همچین بازم طبق حرف داکیومنتیشن، سایز اون‌ها به این صورت محاسبه میشه:یادتونه بالاتر گفتیم که چرایی استفاده از ماکروی PyVarObject_HEAD_INIT رو توضیح میدم و میگم چرا اون فیلد ob_size باید باشه؟ خب همینجا داک بهمون گفته، یبار دیگه با دقت بخونیدش (خطوط قرمز):میگه برای آبجکت‌های variable-length این فیلد ob_size باید باشه، چرا؟ چون ما برای محاسبه‌ی سایز اون آبجکت به N که *length* عه اون آبجکت هست نیاز داریم که اون مقدار length در ob_size ذخیره شده. اینجا رو نگاه کنید:که همونطور که مشخصه، ۸ تا ۸ تا اومده روی سایز تاپل.حالت دومی هم که برای tp_itemsize اتفاق میوفته، اینه که اون آبجکت variable-length نباشه و اصطلاحا statically allocated type objects باشه و در اون صورت این فیلد باید برای اون آبجکت 0 در نظر گرفته بشه، مثل همین *تایپ* خودمون:تابع tupledealloc برای فیلد tp_dealloc:این تابعی که اینجا مشخص شده، عمل نابود کردن اون آبجکت از مموری رو انجام میده، اینکه بایت‌هایی که اون گرفته رو آزاد کنه و...نکات جالبی که توی داکیومنتیشن بهشون اشاره شده:این تابع برای تایپ‌هایی که هیچوقت از بین نمیرن، یعنی None و Ellipsis، تعریف نمیشه!۲.   برای نکته‌ی دوم اول این تیکه کد از tupledealloc رو ببینید:می‌بینید که یک حلقه‌ (به تعداد آبجکت‌هایی که اون تاپل داخل خودش نگه داشته بود (Py_SIZE در واقع len اون آبجکت رو بر میگردونه)) داره یکی از رفرنس‌های آبجکت‌هایی که تاپل داخل خودش نگه‌ داشته بود، کم میکنه. و البته طبیعیه که این رو ما ببینیم، تاپل داره از مموری پاک میشه و باید آبجکت‌هایی که نگه‌داشته بود، رفرنس‌هاشون یکی کم بشه، چون دیگه تاپلی وجود نخواهد داشت که اونا رو نگه دارهمی‌بینید، وقتی که s رو توی یک تاپل گذاشتیم، یکی به رفرنس‌هاش اضافه شد و وقتی تنها اسمی که به اون تاپل اشاره می‌کرد رو حذف کردیم، اون رفرنس هم از s کم شد.حال داکیومنتیشن چی میگه:۳.  اما داکیومنتیشن حرف‌های دیگه هم برای *چطور نوشتن* این تابع داره:که همه‌شون به ترتیب در tupledealloc رعایت شدن:تابع tuplerepr برای فیلد tp_repr:این تابع طبق حرف داکیومنتیشن:اما خطوطی که زیرشون خط کشیده شده، یکی از best practiceهایی که هست که در مورد نوشتن __repr__ هست: این تابع باید مقدار str عی رو برگردونه که در شرایط مناسب، اگر اون به تابع eval پاس بدیم اون instance رو برامون بسازه؛ اما چیزی که کمتر شنیده شده اینه که اگر مقدور نبود باید مقدار str عی رو برگردونه که اولش &lt; و آخرش &gt; باشه که تایپ و ولیو‌ عه آبجکت رو به ما بگه.مقادیر tuple_as_sequence:این فیلد که Sequence Protocol رو برای تاپل مشخص میکنه، این sub slot‌ها رو داره:این یعنی تاپل‌ها:مقدار len دارن و میتونیم به تابع len اون‌ها رو پاس بدیممیتونیم اون‌ها رو با + کانکت کنیممیتونیم از repetition استفاده کنیممی‌تونیم آیتم‌هاشون با ایندکس بگیریمو از عمل‌گر in روشون استفاده کنیممقادیر tuple_as_mapping:اگه تعجب کردید که عه! از اسلایس‌ها که میتونیم روی تاپل‌ها استفاده کنیم پس کوش؟! باید بگم که تابعی که امکان subscript کردن تاپل‌ها رو فراهم میکنه توی این پروتوکل آورده شده:که اگه دقت کنید اسلاید‌هارو پشتیبانی میکنه.تابع tuplehash:این تابع هم که نیاز به هیچ توضیح اضافه‌ای نداره:اگه بریم تایپ لیست رو ببینیم:که به این می‌رسیم:ارور اشنایی هست، نه؟ ?تابع PyObject_GenericGetAttr:طبق حرف داکیومنتیشن:اما به طور خلاصه، این تابع روال عادی گرفتن یک attribute از یک آبجکت رو implement می‌کنه.فیلد tp_doc با مقدار:این فیلد مقدار __doc__ رو ست میکنه و در واقع همون چیزیه که تابع help هم ازش استفاده میکنه:فیلد tp_richcompare و تابع tuplerichcompare:تابعی که در این فیلد قرار میگیره، ساپورت عمل‌های مقایسه‌ای رو برای اون تایپ میاره:فیلد tp_iter و تابع tuple_iter:فرض کنید می‌خوایم یک کلاسی بنویسیم که بتونیم روش حلقه‌ی for بزنیم، باید چی کار کنیم؟ می‌رسیم به تعریف Iterableها:آبجکت‌های iterable به زبان ساده، آبجکت‌هایی هستند که وقتی به تابع iter اون‌ها رو پاس بدیم یک آبجکت iterator به ما بدن! در داکیومنتیشن پایتون باز هم اشاره شده که Containerها اگه میخوان iterable باشن باید متد __iter__ رو implement کنند و خب در C layer، اون تایپ باید تابع مناسبی رو به slot عه tp_iter بده:پس تا اینجا متوجه شدیم (و البته می‌دونستیم) که تاپل یک container عه iterable عه!حال، آبجکت iterator چیه؟به آبجکتی که این دو متد رو پیاده‌سازی کنه، میگن یک Iterator.حالا بیاید یه مرور کنیم: اگه میخوایم (برای مثال) روی یک آبجکت حلقه‌ی for بزنیم، اون آبجکت باید __iter__ رو داشته باشه، __iter__ چی برمیگردونه؟ یک Iterator. وظیفه‌ی iterator چیه؟ اینه که هر باری که روش next رو صدا می‌زنیم (حلقه‌ی for خودش این کار رو میکنه) یک آیتم بهمون برگردونه و وقتی دیگه آیتمی نبود، StopIteration رو raise کنه. حالا بریم ببینیم این اتفاق برای تاپل‌ها چجوری اتفاق میوفته.اول از همه __iter__:که این تابع هست:دقیقا طبق گفته‌های داک، صرفا داره یک iterator رو بر میگردونه.حالا بریم ببینیم اون iterator که از تایپ PyTupleIterObject_ هست، چیه:یه PyObject_HEAD که راجع بهش حرف زدیم، یک index و یک PyTupleObject همین D:اما ماهایی که داریم این مقاله رو می‌خونیم دقت داریم که این یک آبجکت هست و خب چیزی که *باید* داشته باشه چیه؟ بلی باید یک تایپ داشته باشه (که اون ob_type داخل PyObject ست بشه دیگه)حالا تایپ این IterObject چیه:که چیزی که برای  مهمه، دقیقا همین تابع tupleiter_next هست. بریم این تابع رو هم ببینیم:که خیییلی ساده‌ست. اگه دقت کنید یک IterObject میگیره و از فیلد index اش استفاده میکنه و آیتم بعدی رو با PyTuple_GET_ITEM میگیره و ریترن‌ش میکنه.فیلد tp_methods:این فیلد متد‌هایی که اون تایپ داره رو در خودش ذخیره میکنه، برای مثال برای تاپل‌ها ما متد index رو داریم، اون اینجا تعریف میشه:که این ماکرو عه:که در نهایت می‌رسیم به این تابع (تابع tuple_index این تابع رو صدا میزنه):می‌بینید یه حلقه‌ی for که دونه دونه آیتم‌ها رو بررسی میکنه و اگه پیداش کرد index رو برمیگردونه.فیلد tp_new:و در نهایت تابعی که یک آبجکت جدید تاپل می‌سازه:این تابع مسئول ساختن آبجکت جدید تاپل هست و در واقع __new__ عه اون تایپ محسوب میشه.ارتباط بین تایپ‌ها و آبجکت‌ها صرف تعریف و نوشتن یک C struct که میگه این آبجکت قراره چه فیلد‌هایی داشته باشه، باعث ساخته شدن و تعریف شدن یک آبجکت یا تایپ جدید در پایتون نمیشه، یکی از فیلد‌های ضروری عه PyObject فیلدِ ob_type هست که در واقع این struct عه مهم قراره اون آبجکت رو تعریف کنه، ساختن نابود شدنش رو مشخص کنه، بگه چه پروتوکل‌هایی رو پشتیبانی می‌کنه و... پس میشه اینطور نتیجه گرفت که: از بهم وصل کردن یک آبجکت (که PyObject_HEAD داره) و تعریف فیلد ob_type اون از نوع struct عه PyTypeObject، یک آبجکت یا تایپ جدید در پایتون داریم که میتونیم ازش استفاده کنیم.??? که یک چنین چیزی میشه:اگر می‌خواهید تایپ خودتون رو بنویسید و توی Python ازش استفاده کنید این tutorial می‌تونه به شما کمک کنه: https://docs.python.org/3/extending/newtypes_tutorial.html امیدوارم لذت برده باشید.</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Sat, 15 Jul 2023 17:45:24 +0330</pubDate>
            </item>
                    <item>
                <title>متد list.append در C lever مفسر پایتون، چگونه اجرا می‌شود؟</title>
                <link>https://virgool.io/@liewpl/how-append-works-gp4apwtpr0bt</link>
                <description>معمولا دیتاتایپ لیست از اولین دیتاتایپ‌هایی‌ست در آموزش‌های پایتون تدریس می‌شود و باتبع متد append جزو اولین متد‌کال‌هایی‌ست که توسط ما انجام می‌شود. اما اینجا لیست CPython هست و می‌خواهیم بررسی کنیم under the hood واقعا چه چیز‌هایی آبجکتی رو به یک لیست در پایتون اپند می‌کنند.در این مقاله بررسی می‌کنیم:خاصیت dynamic size بودن لیست‌های پایتون به صورت تئوری چگونه پیاده‌سازی شده؟این بحث تئوری از چه الگتوریتمی (پایتون ۳.۸ به قبل) به چه الگوریتمی (پایتون ۳.۹ به بعد) رسیده است؟ و این الگوریتم‌ها دقیقا در مفسر چگونه اجرا می‌شوند؟خاصیت dynamin size بودن لیست‌های پایتون به صورت تئوری چگونه پیاده‌سازی شده؟در این قسمت از مقاله به بررسی یک کانسپت به نام dynamic arrays و چگونگی پیاده‌سازی آنها می‌پردازیم!کانسپت Dynamic ArrayWikipedia:In computer science, a dynamic array, growable array, resizable array, dynamic table, mutable array, or array list is a random access, variable-size list data structure that allows elements to be added or removed. It is supplied with standard libraries in many modern mainstream programming languages. Dynamic arrays overcome a limit of static arrays, which have a fixed capacity that needs to be specified at allocation.A dynamic array is not the same thing as a dynamically allocated array or variable-length array, either of which is an array whose size is fixed when the array is allocated, although a dynamic array may use such a fixed-size array as a back end.[1]چگونه انجام می‌شود؟خیلی ساده اگر بخواهیم به موضوع نگاه کنیم اینجوریه که ما یه مقدار حافظه رو اشغال می‌کنیم، فرضا داخل یه C Array و فرضا اندازه ۴ تا خونه، بعدش آبجکت‌هامون رو توش ذخیره می‌کنیم، و وقتی که ۴ تا خونه‌ش پر شد، میایم یه C Array دیگه می‌سازیم اما مثلا به اندازه‌ی ۸ تا خونه و سپس تمامی مقادیر رو میریزیم توش، و همین‌طور تا آخر.و چیزی که ویکی‌پدیا میگه:A simple dynamic array can be constructed by allocating an array of fixed-size, typically larger than the number of elements immediately required. The elements of the dynamic array are stored contiguously at the start of the underlying array, and the remaining positions towards the end of the underlying array are reserved, or unused. Elements can be added at the end of a dynamic array in constant time by using the reserved space, until this space is completely consumed. When all space is consumed, and an additional element is to be added, then the underlying fixed-size array needs to be increased in size. Typically resizing is expensive because it involves allocating a new underlying array and copying each element from the original array. Elements can be removed from the end of a dynamic array in constant time, as no resizing is required. The number of elements used by the dynamic array contents is its logical size or size, while the size of the underlying array is called the dynamic array&#x27;s capacity or physical size, which is the maximum possible size without relocating data.[2]A fixed-size array will suffice in applications where the maximum logical size is fixed (e.g. by specification), or can be calculated before the array is allocated. A dynamic array might be preferred if: - the maximum logical size is unknown, or difficult to calculate, before the array is allocated - it is considered that a maximum logical size given by a specification is likely to change- the amortized cost of resizing a dynamic array does not significantly affect performance or responsivenessمثل این تصویر در جا‌هایی که یک لاک‌پشت هست (بخاطر پیچیدگی زمانی O(n)) آرایه‌ی قبلی به داخل یک آرایه‌ی جدید با سایز بزرگ‌تر کپی شده! هر چند این realloc کردن همیشه هم O(n) نیست و اگر امکانش باشه، این تابع اون فضا رو extend میکنه پس چنین چیزی هم باید یک‌جایی از آبجکت لیست پایتون پیاده‌سازی شده باشه که در این مقاله در دو ورژن از پایتون (۳.۸ و ۳.۱۱) کاملا با نگاه به کد‌های مفسر بررسیش می‌کنیم.اما یک موضوع دیگه که هست مسئله‌ی اینه که این زیاد شدن با چه نرخی انجام میشه؟! طبق جدولی که در ویکی‌پدیا هست در زبان‌‌های مختلف نرخ رشد این نوع از آرایه‌ها چنینه:پایتون ۳.۸بررسی C API لیست و توابع موجود آن.اول از همه بیاید یه نگاهی به خود آبجکت لیست بندازیم؛ با توجه به داکیومنتیشن پایتون:در C layer آبجکت‌های پایتون، برای آبجکت list ما تایپ PyListObject رو داریم.و خب کد این تایپ در مفسر پایتون:که البته این ماکرویی که در ابتدای این تایپ هست، اینه:که اگه بخوایم کل آبجکت لیست رو یکجا ببینیم (این کد وجود نداره و صرفا برای ساده‌سازی و کنار هم آوردن همه فیلد‌ها نوشته شده):فیلد ob_base برای cast کردن آبجکت و اشاره کردن بهش با *PyObject استفاده میشه، فیلد ob_size دقیقا مقدار len رو نگه میداره، ob_item پوینتر‌هایی که از جنس PyObject که درون لیست ذخیره شدن رو نگه میداره و چیزی که برای ما مهمه:‌ allocated هست که مقداریه که لیست *در واقع* از حافظه اشغال کرده رو نشون میده. از allocated برای کنترل و resize کردن لیست استفاده میشه. در مطالعه‌ کد‌های فایل listobject.c اولین نشانه و تابعی که برای انجام عملیات append این پیدا میشه، اینه: وقتی که شما روی یک آبجکت لیست، در کدهای پایتون‌تون، متد اپند رو صدا می‌زنید این تابع صدا زده میشه.بسیار ساده، ابتدا آبجکت لیست و آبجکتی که باید بهش اضافه بشه رو میگیره و تابع app1 رو صدا میزنه، اگه خروجی app1 صفر باشه یعنی اپند انجام شده و مقدار None ریترن میشه، اگر نه، مقدار NULL به نشانه‌ی ارور و عدم انجام اپند (به هر دلیلی) ریترن میشه.بریم تابع app1 رو نگاه کنیم:کد بسیار ساده‌ی تابع app1 که مهم‌ترین قسمتش خط ۳۴۶ هست! که خب می‌دونیم باید برای اپند کردن یک resize انجام بدیم.این هم کل تابع list_resize:آقای ریموند هتینگر حدود ۲۰ سال پیش این تابع رو optimize کردن و روش ایشون تا پایتون ۳.۸ استفاده می‌شد:تریس کردن توابع CPython موقع یک اپند.حالا که تمامی توابع برای اپند کردن به یک لیست رو داریم بیاید تا این کد رو اجرا کنیم:برای اینکه کامل و با شکل متوجه بشیم چه اتفاقی میوفته من از روی کد‌های C بالا یه نسخه‌ی مینیمال پایتونی نوشتم که از یه Debugger خوب هم بتونیم استفاده کنیم.کد‌‌هایی که قراره استفاده کنیم اینجان: https://github.com/mahdihaghverdi/listappend از تریک‌ها و روش‌های پایتونی استفاده نکردم تا دقیقا همون کد‌های سی رو بنویسم، پس بریم که این اپند کردن رو یبار trace کنیم:در ابتدا همه‌چیز طبق چیز‌هایی پیشفرضی هست که توی کلاس PyListObject نوشته شدن:سپس متد append صدا زده میشه و این متد تابع list_append رو صدا میزنه:تابع list_append:و خب طبق کد این تابع، تابع app1 رو صدا میزنه:اتفاقاتی که میوفته:خط اول تابع مقدار len تابع رو با اون تابع بدست میاره! سپس چک میکنه که آیا به سر حد نهایت اندازه یه لیست که اون عدده (که فکر کنم بزرگ‌ترین عدد ۳۲ بیتی هست، ولی مطمئن نیستم) رسیده یا نه! که اگه رسیده یک اکسپشن raise کنه!سپس روند execution ما می‌رسه به تابع list_resize:اتفاقاتی که میوفته:ابتدا مقدار allocated رو میگیره، سپس چک میکنه ببینه میتونه بدون resize کردن اون لیست میتونه ادامه بده یا نه، یعنی لیست هنوز جای خالی توش مونده یا خیر!این هم به این شرط وابسته‌ست که allocated ما بیشتر از newsize که سایز جدید لیست ماست باشه (که اینجا len + 1 هست) و اینکه اون newsize بیشتر یا مساوی نصف مقدار خالی باشه! که البته اینجا توی کد ما رد میشه!سپس مقدار new_allocated محاسبه میشه:که طبق پنجره‌ی دیباگر مقدار ۴ هست. محاسبه‌ی این مقدار فرمول ساده‌ای داره که میگه:اندازه جدید لیست (len اش) + جز صحیح یک هشتم مقدار جدید + (۳ اگر مقدار جدید کمتر از ۹ باشه و در غیر این صورت + ۶) (فرمولی که Raymond Hettinger داده دیگه چه کنیم D:)می‌رسیم به شرط بعدی که چک میکنه آیا این مقدار new_allocated خییییلی بزرگ شده یا نه که اگه شده اکسپشن بده که در کد ما اینطور نیست! (البته اشاره کنم اون ۱ در کد سی این بود sizeof(PyObject *) که خب نمیدونستم چقدره و بجاش عدد یک رو گذاشتم)سپس:میاد باز چک میکنه که آیا اندازه جدید به اندازه کافی کوچک هست یا خیر و اگه بود کار مهمی رو انجام بده:‌‌ کپی کردن مقادیر به مکانی با اندازه‌ی جدید. این کار توسط تابع PyMem_Realloc انجام میشه.حالا مقداری جدید باید محاسبه بشه که مقدار بایت‌هایی هست که تابع بعدی باید از مموری بگیره، مقدار واقعی این در کد CPython همون new_allocated * sizeof(PyObject *) هست که ما اون رو برابر با یک گرفتیم:درون تابع PyMem_Realloc:که خب کاری که من کردم این بود که به تعداد مورد نیاز (new_allocted_byted - len(self)، که یعنی مثلا الان لیست من ۴ تا عضو داره و new_allocated میگه باید ۸ تا بشی، که خب ۴ تا خونه‌ی خالی باید بهش اضافه بشه)‌ و برای نشون دادن خونه‌ی خالی از &#x27;*&#x27; استفاده کردم که:یک سری چک‌های ساده دیگه انجام میشه و می‌رسیم به:مشاهده می‌کنید که مقدار ob_item این لیست ما بروز شده و سپس:حالا مقدار len که فیلد ob_size نشونش میده بروز شده و:مقدار allocated هم بروز میشه و صفر به معنای انجام موفق عملیات ریترن میشه!اما خب کی قراره آبجکت داخل لیست ریخته بشه؟ دقیقا اینجا:این تابع میاد و:مقدار &quot;Py 3.8&quot; رو داخل اولین ایندکس لیست میگذاره و در نهایت None ریترن میشه!به همین سادگی و زیبایی عمل اپند کردن به یک لیست انجام شد :دی اما خب این به یک لیست خالی بود، معلومه که باید یه resize انجام بشه، لیست‌های پر‌تر چطور؟ این اتفاقیه که میوفته و اگه در تعداد خیلی بالاتر بخوایم بهش نگاه کنیم میزان رشد و نحوه‌ی رشدش به صورت خواهد بود:اما این اعداد و ارقام به چه معنی‌ای هستن؟این اعداد نشون میدن که وقتی سایز لیست‌ ما، ۱۸۴ بایت هست، وقتی که یک resize می‌خواد صورت بگیره، اندازه‌ی ۸ خانه‌ خالی resize انجام میشه، یا مثلا وقتی سایز لیست میرسه به ۵۲۰ بایت، list_resize اندازه‌ی ۱۲ خونه‌ی خالی میذاره روی ob_item یا توی ۷۶۰ بایت، ۱۴ خونه‌ی خالی به ob_item اضافه میشه و الی آخر...این نمودار از روی داده‌های تولید شده توسط implementation پایتونی من از append و با این استفاده از این تابع کشیده شده:حالا بیاید نتایج پیاده‌سازی خودمون رو با نتایج بدست اومده اجرا کردن این کد: که با پایتون ۳.۸ ران شده ببینیم:انگار واقعا شبیه به هم هستن، پس بیاید بندازیم‌شون روی هم:بلی دقیقا روی هم افتادن :)) خودم هم باورم نمیشد دقیقا همین نتایج رو بگیریم D:این از ورژن پایتون ۳.۸مون بریم ببینیم بعد از این نسخه، چه اتفاقاتی افتاده و این الگوریتم چقدر بهتر شده؟پایتون ۳.۱۱در git blame فایل listobject.c برنچ main پایتون چنین چیزی مشاهده میشه:یه کسی ۳ سال پیش، برای پایتون ورژن:یه بحثی رو اینجا: https://bugs.python.org/issue38373 با کور دولوپرا داشته که نتیجه‌ی کلیش این شده که، استراتژی list_resize رو تغییر بدن به:می‌بینید که هم pattern رشد و هم فرمول محاسبه‌ی new_allocated تغییر کرده، دلایلش در همون باگ‌ترکر بالا ذکر شده اما نتایجش قابل توجه هستن.اول بیاید ببینیم رفتن اپند کردن به یک لیست در پایتون در ورژن ۳.۱۱ چه تغییراتی داشته:چندین تابع جدید برای هندل کردن اپند کردن به پایتون اضافه شدن که ترتیب صدا زدن‌شون و خودشون (کدشون) به این صورته:تابع list_append الان تابع_PyList_AppendTakeRefرو صدا میزنه. این تابع چنینه:همین‌طور که مشخصه این تابع بعد از چک کردن چند تا چیز و گرفتن مقادیر len و allocated یه شرط داره! اونم اینه که اگه allocated بیشتر بود، len رو یکی بیشتر کن و مقدار رو بذار توی لیست و خلاص! اما اگر مقدار allocated بیشتر از len نبود، میریم سراغ صدا زدن تابع بعدی:اول که مقدار len رو دریافت میکنه، سپس چک میکنه که یا allocated عدد ۱- باشه (که توی PyListObject نوشته بود وقتی مثلا list.sort رو صدا میزنیم این چنین میشه) یا اینکه allocated با len برابره؛ حالا میاد و list_resize رو صدا میزنه!تا اینجا تغییری نداشتیم ولی طبق همون pr عی که اون فرد داده بود و فرمول رو عوض کرده بود:باز هم مثل قبل بیاید یه مثال بزنیم و کدی رو ران کنیم تا بفهمیم این فرمول جدید چجوری کار میکنه.من باز هم کد پایتون این لاجیک جدید رو نوشتم که توی همون ریپازیتوری هست.دیگه بدون توضیح اضافه دیباگ کردنش رو ببینیم:حالا بیاید ببینیم اگه allocation به اندازه‌ کافی بزرگ باشه چه اتفاقی میوفته:این هم از بررسی کد‌هایی که در ورژن ۳.۱۱ یک آبجکت رو به لیست اپند می‌کنند. اما خب سوالی که پیش میاد، این تغییر محاسبه‌ی new_allocation چه تاثیری داشته؟بیاید تا دو نموداری که از اعداد پایتون ۳.۱۱ و ۳.۸ تولید شدن رو بندازیم روی هم دیگه و تفاوت رو واضح ببینیم:خط نارنجی پایتون ۳.۱۱ هست :)بازم یک توضیح کوچک: خط نارنجی رنگ میگه: وقتی که سایز لیست از ۷۶۰ بایت تا ۹۰۴ بایت تغییر میکنه، برای هر بار resize که صورت میگیره، تنها ۱۶ خونه به ob_item اضافه میشه.اما خب این اعداد فقط برای ۱۲۸ تا عدد هست، بیاید تا مقدار تا ۴۶۰ تا آبجکت ببریم بالااین هم مقایسه‌ای بین growth rateهای این دو الگوریتم.توی این مقاله سعی کردم خیلی ساده و با کلی کد ساده‌تر و نتایج لحظه به لحظه بهتون نشون بدم در یک اپند واقعا چه رخ میده.امیدوارم استفاده کرده باشید!</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Sat, 01 Jul 2023 00:09:02 +0330</pubDate>
            </item>
                    <item>
                <title>پایتون «بسیار» سریع است!</title>
                <link>https://virgool.io/@liewpl/python-is-very-fast-gmmdjs3zyhob</link>
                <description>اول بیاید یک مقایسه کوچک انجام بدیم:مقایسه زمانی «مجموع اعداد یک دنباله»در تصویر بالا جمع اعداد حسابی از صفر تا یک میلیارد رو :با استفاده از حلقه for در پایتونبا استفاده از تابع built-in عه «sum»با استفاده از مورد اول + numbaآیا پایتون کند است؟ خیر به شرطی که از ابزار درستی استفاده کنید!اما ببینیم چرا؟مقایسه مورد اول و دوم:    در کل وقتی کد پایتون داره execute میشه، اتفاقی که میوفته اینه: بایت‌کد‌های تولید شده از کد شما درون یک حلقه و switch statement خیلی بزرگی در فایل ceval.c قرار میگیره، هربار یک بایت‌کد وارد حلقه میشه و کد مخصوص اون بایت‌کد در switch statement پیدا میشه و ران میشه.    ران شدنش هم راحته، صرفا چند تا تابع به زبان سی قرار اجرا بشه (می‌تونید توی داکیومنتیشن C API پیداشون کنید.)    سوال اینجاست که حالا که کد‌های سی اجرا میشن چرا در مورد اول (pure_summer) کد، کُند هست اما sum_summer خیلی سریع‌تر هست؟    در واقع بیشترِ زمانیکه در مورد اول تلف شده بخاطر وجود همون حلقه و switch statement بزرگ در ceval.c هست. تابع pure_summer در کل ۱۵ بایت‌کد تولید میکنه که ۷ تاش مال تابع for و عامل کندکننده کد ماست! هر بار iteration در ceval.c برای ما هزینه داره و  وقت رو تلف میکنه و روی هم رفته باعث کند شدن تابع اول میشه. (۷ تا بایت‌کدِ مربوط به حلقه قراره چندبار اجرا بشن و تبعا قراره چند بار iteration در ceval.c اتفاق بیوفته؟؟)بایت‌کدهای تولید شده برای تابع pure_summer    اما در مورد دوم (sum_summer) ما ۶ تا بایت‌کد تولید شده داریم:پایتون این ۶ تا رو اجرا میکنه و ما نتیجه رو داریم، فرقش با بالایی چیه؟ ۱. تابع sum یک تابع built-in هست و یک حلقه به زبان C داره که کاملا مشخصه که از حلقه پایتون سریع تره۲. پایتون دیگه قرار نیست پشت سر هم به دفعات زیاد iteration داشته باشه. صرفا در یک iteration تابع رو صدا میزنه و اون تابع درون خودش یه حلقه زبان سی داره و وقتی کارش تموم شد نتیجه رو به پایتون میده. این دو فاکتور باعث میشن که مورد دوم بسیار سریع‌تر از مورد اول باشهPython with built-in &#x60;sum&#x60; vs. Pure Python ≃ 3.75 times fasterمقایسه مورد اول و سوم    مورد سوم که دارای یک دکوریتور به اسم numba.jit@ هست، قضیه‌اش کمی با باقی توابع فرق داره، وقتی که میایم به بایت‌کد تولیدی این تابع نگاه می‌کنیم می‌بینیم که هیچ تفاوتی با تابع اولی نداره، اما قرار نیست این بایت‌کد‌ها اجرا بشن.    وقتی این تابع رو دکوریت میکنیم چنین آبجکتی رو بجای تابع معمولی استفاده میکنیم:این چیزی هست که اون دکوریتور jit برای ما تولید میکنه و همین قراره اجرا بشه، اما JIT چی هست اصلا؟JIT Compilerکامپایلرهای JIT، کامپایلر‌هایی هستن که وقتی که کد داره اجرا میشه، قسمت‌هایی از کد که دارای حلقه‌های سنگین و محاسبات بالا (اغلب عددی) هستن، و یا نقاطی که زیاد اجرا میشن، مثلا یک تابع که دفعات زیادی اجرا میشه، یا جاهایی که به اصطلاح نقاط داغ کد ما هستن رو پیدا میکنن و اونارو به چیز دیگه‌ای، یک کد native و بسیار optimize شده، کامپایل می‌کنن. زبان‌ها و ران‌تایم‌هایی که از JIT استفاده میکنن: یک. جاوا دو. سی‌شارپ سه. NodeJS و در دنیای پایتون:‌ یک. مفسر PyPy،  دو. مفسر Pyjion و سه. چیزی به اسم numba که مفسر نیست و صرفا یک JIT Compiler هست که در CPython می‌تونیم استفاده کنیم.    در مورد سوم هم دقیقا این اتفاق افتاده، ما تابع رو با دکوریتور jit، دکوریت کردیم  و نامبا اون رو با یک کد خیلی خیلی سریع جایگزین کرده و وقتی که اجراش میکنیم، پایتون صرفا اون کد رو به سی‌پی‌یو و سی‌پی‌یو نتیجه رو به پایتون میده و پایتون به ما برش می‌گردونه.    جیت کامپایلر numba توسط کسی نوشته شده که NumPy رو نوشته، و مزایا و محدودیت‌های خودش رو هم داره، این JIT Compiler برای سریع‌کردن قسمت‌هایی از کد استفاده میشه که محاسبات عددی و چنین حلقه‌هایی که در مقایسه‌مون دیدیم، داشته باشن؛ پس همه‌جا نمیشه از این JIT Compiler استفاده کرد، اما اگه در جای درستش استفاده کنید پیشرفت:Python + numba vs. Pure Python ≃ 5,880,000 times fasterPython + numba vs. Python built-in &#x60;sum&#x60; ≃ 1,746,666 times faster«خیلی» بزرگی رو خواهید دید.جیت compiler‌ها هم مزایا و هم معایبی دارن. از مزایاشون میشه به همین افزایش نجومی سرعت بخش‌هایی از کد ما اشاره کرد. از معایب‌شون:۱. وقتی از JIT Compiler استفاده میکنید، قراره بی شک مموری بیشتری استفاده کنید، بنچ‌مارک‌های مختلفی وجود داره، مثلا در یکی که الگوریتم n-body رو در چند زبان برنامه‌نویسی مقایسه کرده بود، جولیا در این بنچ‌مارک ۴.۲۱ ثانیه، NodeJS در 8.55 ثانیه،  پایتون (CPython) در 9 دقیقه اون رو تمام کرده بودن.اما میزان استفاده از مموری رو اگه نگاه کنیم: جولیا عدد ۲۲۶۴۲۰ نود ج‌اس ۳۹۹۵۶ و پایتون ۷۷۸۰ (واحدش رو نمیدونم) رو داشتن که:نود جی‌اس بیش از ۵ برابر و جولیا بیش از ۲۹ برابر مصرف مموری بیشتری داشتن. https://benchmarksgame-team.pages.debian.net/benchmarksgame/performance/nbody.html ۲. جیت کامپایلر‌ها اندکی start-up رو کند میکنن، چون jit compiler ها برنامه‌های پیچیده‌ای هستن و تا بیان به خودشون بجنبن و کاملا ران بشن، طول می‌کشه. این رو میشه در همون عکس از بنچ‌مارک ببینید، در اولین اجرای jit_summer ما یک زمان رو مشاهده می‌کنیم و در دومین یک زمان دیگه؛ زمان اصلی‌ای که باید در نظر بگیریم اون دومی هست. چرا؟ چون در بار اول نامبا باید تابع رو دریافت کنه، تصمیم بگیره و سپس یک کد خیلی سریع براش تولید کنه و بعد پایتون اون رو اجرا کنه؛ اما نامبا این کد رو cache میکنه و بار دوم فقط اون کد اجرا میشه و ما زمان واقعی اجرا شدن اون تابع رو می‌بینیم.دلیل اصلی‌ای که پایتون در این بنچ‌مارک کند ظاهر شده دقیقا همون دلیلی هست که برای مورد اول گفتیم. این الگوریتم خیلی پیچیده‌ای نیست اما محاسبات و tight loopهای سنگین و زیادی داره که باعث میشه وقت تلف شده زیادی رو در پایتون شاهد باشیم.۳ ویدیو خیلی خوب که بهتره ببینیدشونMake Python Code 1000x Faster With NumbaAccelerating Scientific Workloads with Numba - By a Core Developer of Numba ProjectHow to Accelerate an Existing Codebase With Numba | SciPyیک مشکل مهمهمه‌مون می‌دونیم که هر چیزی رو بهر کاری ساختن، و نمیشه از یه چیزی همه‌جا استفاده کرد؛ این جمله برای نامبا هم دقیقا صدق می‌کنه. بیاید تا چند تا مثال رو ببینیم:در این مثال ساده یک تابع داریم که یک ورودی لیست داره که برای هر عضو چک میکنه که آیا زوج هست یا نه، اگه زوج بود که عدد دو رو به یک لیست دیگه append میکنه، اگه نه استرینگ ۱ رو. و بعدش اون لیست رو به ما میده.ابتدا با پایتون اجراش میکنیم، یک میلی ثانیه و تقریبا ۴ دهم میلی ثانیه طول میکشه تا اجرا بشه.حالا بیاید این تابع رو جیت کامپایل و اجرا کنیم:با یک warning طویل و قرمز رو به رو میشیم :(یکی از مهم‌ترین چیزایی که توی این warning می‌بینیم همین خطی هست که نوشته object mode compilationاگه با نامبا کار میکنید و این اخطار رو دریافت کردید بدونید که هیچ افزایش سرعتی عاید شما نمیشه.خب برای اولین بار که قبلا هم صحبت کردیم وقت سر کامپایل شدن اون تابع می‌گذره بیاید تا دوباره اجراش کنیم:می‌بینیم که از نسخه pure Python اش خیلی کندتر هست.این رفتار نامبا چند دلیل داره. اگه بریم و اون اخطار رو بخونیم متوجه میشیم اولین دلیلش اینه که ما یبار به لیست عدد وارد کردیم و یبار string. خب این رفتار اشتباهی هست چون نامبا میخواد یک کد خیلی efficient عه low level برای محاسبه عددی تولید کنه، می‌بینه عه یه استرینگ داره به لیست اضافه میشه و همه‌چیز بهم میریزه. دلیل دومش هم اینکه نامبا با لیست‌های پایتون رابطه خوبی نداره یک دلیلش اینه که هر آبجکتی میشه بهشون اضافه کرد که دقیقا اشکال کار ما در دلیل اول همین بود، دو اینکه یک سایز فیکس نداره و این برای کارها و بهینه‌سازی‌های مربوط به مموری کار رو خراب میکنه.بخاطر این دو دلیل نامبا یک کد به کندی کد پایتون ما تولید میکنه، و بخاطر overheadعی هم که داره در کل نتیجه کندتر میشه.برای اینکه اندکی بهتر بشه اوضاع این مثال‌مون، ما اینکار رو انجام میدیم:اول از همه اون یک رو به عدد تبدیل میکنیم و سپس از یک دکوریتور دیگه از نامبا به اسم njit استفاده می‌کنیم، این دکوریتور دقیقا همون دکوریتور jit قبلی هست اما یک آرگومان رو برای ما جلو جلو پاس داده و اون آرگومان:nopython=Trueهست. کاری که این آرگومان انجام میده اینکه نامبا دیگه از آبجکت‌های پایتون و C API عه پایتون استفاده نمیکنه و در اکثر مواقع توصیه میشه از همین دکوریتور استفاده کنید. اما وقتی این رو ران میکنیم به یک اخطار دیگه‌ برخورد میکنیم و این دفعه مشکل زیر سر لیست ورودی ماست.ارور میگه من از حالتی به اسم reflected list استفاده میکنم. این حالت بخاطر همون مشکل نامبا با لیست‌های پایتون هست و اگه برای بار دوم این رو ران کنیم:باز هم یه نتیجه خیلی بد میگیریم.راه حل چیه؟باید از برادر بزرگ‌تر نامبا به اسم نام‌پای NumPy استفاده کنیم :))بجای یک لیست معمولی از تابع arange عه نام‌پای استفاده می‌کنیم، وقتی تابع اولیه مون رو ران میکنیم می‌بینیم که نسخه پایتون کند‌تر از قبل ظاهر میشه (دلیلش رو من دقیقا نمیدونم که بهتون بگم) اما وقتی اون رو جیت کامپایل و ران می‌میکنیم یک افزایش سرعت زیادی رو می‌بینیم.Pure Python: 1.71 msPython + Numba: 282 micro sPure Python vs. Python + Numba =&gt; about 6 times faster کار با نامبا بعضی وقتا حساسیت‌های زیادی داره و همین‌جوری نمیشه همه‌چیز رو سریع‌تر کرد، باید داکیومنتیشن‌اش رو بخونید، ویدیوهای متفاوت و کد‌های دیگه رو ببینید تا بتونید به خوبی ازش استفاده کنید.سیستمی که ازش برای تست گرفتن استفاده کردم:OS: Debian GNU/Linux 11 (bullseye) x86_64Kernel: 5.10.0-12-amd64 CPU: AMD Ryzen 7 3700U with Radeon Vega Mobile Gfx (8) @ 2.300Python: Python 3.9.2 (default, Feb 28 2021, 17:03:44)  [GCC 10.2.1 20210110] on linuxمعرفی «نامبا»نامبا پایتون را سریع می‌کند.نامبا یک JIT Compiler متن‌بازه که قسمتی از کد پایتون و NumPy شما را به یک machine code بسیار سریع تبدیل می‌کند.توابع پایتونی را سریع می‌کند    نامبا توابع پایتون را در زمان اجرا به کد ماشین بهینه‌سازی شده با استفاده از کتابخانه استاندارد کامپایلر LLVM ترجمه می کند. الگوریتم های عددی کامپایل شده با Numba در پایتون می توانند به سرعت های C یا FORTRAN نزدیک شوند.    نیازی نیست مفسر پایتون را جایگزین کنید، یک مرحله کامپایل جداگانه اجرا کنید، یا حتی یک کامپایلر C/C++ را نصب کنید. کافیست یکی از دکوریتورهای Numba را روی تابع پایتون خود اعمال کنید و Numba بقیه کارها را انجام می دهد.برای کار‌های علمی ساخته شده استنامبا برای استفاده با آرایه ها و توابع NumPy طراحی شده است. Numba کد تخصصی را برای انواع داده ها و طرح بندی های مختلف آرایه تولید می کند تا عملکرد را بهینه کند. دکوراتورهای ویژه می توانند universal functions ایجاد کنند که مانند توابع NumPy روی آرایه های NumPy پخش می شوند.Numba همچنین با نوت‌بوک‌های Jupyter برای محاسبات تعاملی و با چارچوب‌های اجرایی توزیع‌شده، مانند Dask و Spark، عالی کار می‌کند.الگوریتم‌‌های شمارا موازی می‌کندنامبا طیف وسیعی از گزینه ها را برای موازی سازی کد شما برای CPU و GPU ارائه می دهد، که اغلب تنها با تغییرات جزئی کد همراه است.Simplified Threadingنامبا می تواند به طور خودکار expressionهای آرایه‌های NumPy را روی چندین هسته CPU اجرا کند و نوشتن حلقه های موازی را آسان می کند.SIMD Vectorizationنامبا می تواند به طور خودکار برخی از حلقه‌ها را به vector instructions برای بهبود سرعت تا 2-4 برابر تبدیل کند. Numba با قابلیت های CPU شما سازگار است، چه CPU شما از SSE، AVX یا AVX-512 پشتیبانی کند.GPU Accelerationنامبا با پشتیبانی از درایورهای NVIDIA CUDA و AMD ROCm به شما امکان می‌دهد الگوریتم‌های GPU موازی را کاملاً با پایتون بنویسید.وبسایت نامبا: https://numba.pydata.org/ اطلاعات بیشتر در مورد نامبا: https://numba.readthedocs.io/en/stable/user/5minguide.html کنفرانس‌ها و آموزش‌‌ها: https://numba.readthedocs.io/en/stable/user/talks.html گیت‌هاب: https://github.com/numba/numba سریع برنامه‌نویسی کنید :))</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Mon, 04 Apr 2022 12:51:13 +0430</pubDate>
            </item>
                    <item>
                <title>فریم‌ورک asyncio و TaskGroupها در پایتون</title>
                <link>https://virgool.io/@liewpl/asyncio-and-taskgroups-t598c8poken9</link>
                <description>اواسط ماه پیش، این رشته‌توییت از آقای Yury Selivanov منتشر شد که در داخل صحبت‌هاشون این جمله گفته شد:... I believe that this makes Python one of the best-equipped languages for writing concurrent code. ...من اعتقاد دارم که این باعث میشه پایتون یکی از مجهزترین زبان‌ها برای نوشتن کد‌های concurrent بحساب بیاد.بریم ببینیم اون ضمیر this در این رشتو به چی اشاره داره!! اول بیایید ببینیم ایشون چه کسی هستن؟✔️ آقای Yury Selivanovایشون یکی از core developerهای پرکار پایتون هستن، که عمده فعالیت‌شون برای این PEP‌ها بوده:PEP 492    - async and await syntax    - async with    - async for    - coroutine objectPEP 525    - async generators    - async iteration protocolPEP 530    - async comprehensions    - await in comprehensionsو مشارکت در:PEP 654- ExceptionGroups and except*این هم آدرس صفحه LinkedInشون می‌تونید اطلاعات بیشتری راجع به ایشون اینجا پیدا کنید.حالا که ایشون رو شناختیم و دیدیم که در دنیای async فعالیت زیادی داشتن بریم اون #رشتو رو تحلیل کنیم.ایشون در این رشتو توضیح میدن: چرا به TaskGroupها نیاز داشتیم؟چه چیز(هایی) باید قبل از اون به پایتون اضافه میشد؟از TaskGroupها میشه بجای چه چیزی استفاده کرد؟چرا به TaskGroupها نیاز داشتیم؟بعد از وقتی asyncio منتشر شد، و اون چندتا pepی که ایشون نوشتن به پایتون اضافه شد، دو تا پروژه رو دو نفر دیگه شروع کردن نوشتن، یکی Curio (توسط David Beazley) و دیگری Trio (توسط Nathaniel J. Smith).نویسنده‌های این دو پروژه میخواستن با پایتون مدرن (در زمینه concurrent code، یعنی سینتکس async await و ...) یه بار دیگه یه کتابخونه شبیه به asyncio (ولی بهتر) بنویسن. وقتی که این کار رو کردن، توسعه‌دهنده‌های پایتون فهمیدن که کجاهای asyncio رو میشه بهتر کرد. برای مثال تابعasyncio.run(...)رو از Curio الگو برداری کردن؛ یکی دیگه از چیزهایی که بعد از سال‌ها توسعه‌ی EdgeDB (یکی از جدید‌ترین انواع دیتابیس که توسط آقای Yury selivanov و همکارش Elvis Pranskevichus نوشته شده.) و خوندن source پروژه Trio، در پایتون احساس میشد چیزی بود به اسم TaskGroupها.قبل از اینکه توضیح بدم چرا به تسک‌گروپ‌ها پایتون احتیاج داشت باید بگم وقتی شما چند تا Task رو میخواید باهم await کنید، apiی که الان در اختیار شماست، تابعی هست به اسم asyncio.gather. (در واقع معرفی TaskGroupها برای جایگزین کردن اونها بجای asyncio.gather هست)برای مثال:این تابع میاد و این taskها رو باهم و همزمان await میکنه، و هر چیزی که ازشون برگشت داده شد جمع میکنه و برای ما return میکنه.این تابع یک آرگومان اختیاری هم دریافت میکنه به اسم return_exception که به صورت پیش‌فرض False هست، اما اگر اون رو True قرار بدیم، دیگر هیچ exceptionعی raise نیمشه و آبجکت‌های exceptionهای raise شده درون تسک‌ها به ما برگشت داده میشه:مشکلات ما چی هستن؟یکی از مشکلاتی که این تابع داره، وقتی که در یکی از تسک‌ها یک exception رخ میده، اون رو propagate میکنه، اما باقی تسک‌ها به کارشون ادامه میدن و کَنسِل نمیشن و این یک مشکل هست.مشکل دیگه‌ای که هست وقتی که شما آرگومان return_exception رو True قرار میدید، دیگه‌ هیچ exceptionعی raise نمیشه و فقط آبجکت‌ اونا به ما برگشت داده میشه.این api جالب و جذابی نیست و کارکردن باهاش یه ذره اذیت کننده‌ و سنیگن هست و طبق ذن پایتون:Errors should never pass silentlyچه چیز(هایی) باید قبل از اینکه این مشکلات برطرف بشه به پایتون اضافه میشد؟برای رفع مشکلات بالا باید یک مفهوم و مکانیزمی مثل multi error بوجود میومد: توسعه دهنده‌ها واسه اینکار اومدن چیزی به عنوان ExceptionGroup هارو به پایتون اضافه کردن. با اضافه شدن‌شون، یک سینتکس جدید برای پایتون معرفی شد:که با این قابلیت میشه چند تا exception رو یک‌جا باهم گرفت:در try except قدیمی، حداکثر یک بلاک except می‌تونست اجرا بشه، اما با exception groupها یک بار raise شدن یک ExceptionGroup میتونه باعث execute شدن چندتا بلاک کد *except بشه.الان که ExceptionGroupها رو هم داریم می‌تونیم که با استفاده درست ازشون به خوبی TaskGroupها رو هم داشته باشیم.از TaskGroupها میشه بجای چه چیزی استفاده کرد؟حالا که این هم به پایتون اضافه شد، دیگه میشه راحت از TaskGroupها استفاده کرد؛ کارکردی شبیه به gather اما بهتر و قشنگ‌ترفواید TaskGroupها:اگر یکی از تسک‌ها fail شد، باقی تسک‌ها هم کنسل می‌شوند.امکان اجرای کد با استفاده از await بین تسک‌های زمان‌بندی شده در یک TaskGroup، وجود دارد.به لطف ExceptionGroupها تمامی errorها براحتی propagate میشن، و میشه اون‌هارو handle و گزارش کرد.تسک گروپ‌ها از پایتون ۳.۱۱ به پایتون اضافه خواهند شد.ایشون بعد از این‌همه تجربه و کار در دنیای asyncio در پایتون در این رشتو این جمله رو گفتن:من اعتقاد دارم که این باعث میشه پایتون یکی از مجهزترین زبان‌ها برای نوشتن کد‌های concurrent بحساب بیاد.پایتون انواع و اقسام روش‌ها، رویه‌‌ها و ابزارها و فریم‌ورک‌های نوشتن کدهای concurrent و parallel رو در اختیار ما می‌گذاره؛ اینها براحتی میتونن انواع و اقسام مشکلات رو برای ما براحتی برطرف کنن، از نوشتن کدهای IO bound با asyncio و threading تا موازی سازی و اجرا کردن کدهای CPU bound همچنان با asyncio multiprocessing و subinterpreters وغیره و ذالک.Happy Pythoning :)</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Thu, 17 Mar 2022 22:29:51 +0330</pubDate>
            </item>
                    <item>
                <title>Python Standard Library vs. PyPI</title>
                <link>https://virgool.io/@liewpl/python-standard-library-vs-pypi-mvz4o03jw2sj</link>
                <description>کتابخونه‌هایی که داخل standard library هستن چه تفاوتی با کتابخونه‌هایی که داخل PyPI هستن دارن؟ابتدا موارد لازم برای نوشتن این مقاله رو import و نصب میکنیم.✔️ از چند جهت میشه این سوال رو بررسی کرد و پاسخ داد.✅ از نظر آپدیت شدن: - در stdlib:        کتابخانه‌هایی که وارد استاندارد لایبرری میشن، مجبور هستن که در release schedule عه پایتون قفل بشوند. یعنی برای اضافه کردن فیچر‌های جدید نمیتونن بیرون از release schedule پایتون آپدیت بشن. (البته برای دریافت زودتر بروزرسانی‌هاشون میشه از ورژن‌‌های آلفا و بتا استفاده کرد.) - در PyPI:        اما کتابخونه‌هایی که در PyPI منتشر می‌شوند می‌توانند release schedule خودشان را به هر صورتی که می‌خواهند داشته باشند. و‌ آزادانه آپدیت بشن.         با یه مثال توضیحش می‌دیم! کتابخونه requests وقتی اومد، خیلی محبوب شد و جامعه، از توسعه‌دهنده‌‌های پایتون خواستن که اون رو بیارن توی stdlib. اما دو مشکل وجود داشت:    ۱. وقتی یک لایبرری به stdlib اضافه می‌شه، باید یک یا چند نفر اون رو نگهداری کنن. که هزینه‌برداره!    ۲. علاوه بر مورد قبلی، همون‌طور که گفتیم، دیگه آپدیت شدنش دست خودش نیست و هر آپدیتی که داره، باید صبر کنه تا آپدیت بعدی پایتون. اینجوری سرعت توسعه کم می‌شه و ویژگی‌های جدیدش دیر به دیر به کتابخونه اضافه می‌شن! بویژه که اون زمان، کتابخونه requests هم تند تند آپدیت می‌داد و نمی‌تونست اینقدر صبر کنه!تا اینجا:stdlib 0️⃣ : 1️⃣ PyPI➰➰➰➰➰➰➰➰➰➰➰➰➰✅ سازگاری با ورژن پایتون و داشتن باگ: - در stdlib:        کتابخانه‌هایی که در stdlib هستن، از نقص‌های بسیار کمی برخوردار هستن و حواس توسعه‌دهنده‌های پایتون بهشون هست :) چون از مرحله نوشتن PEP و prototypeهای ساده و طراحی APIهاشون، core developerهای خِبره و زیادی نظراتشون رو به نویسنده (ها) میگن. در ضمن این کتابخونه‌ها همیشه با ورژنی که منتشر میشن سازگاری دارن. - در PyPI:        اما کتابخونه‌هایی که در PyPI هستن در اغلب موارد بعد از منتشر شدن آخرین ورژن پایتون با اون سازگاری ندارن و باید تغییراتی در سورس‌کد خودشون داشته باشن. از نظر داشتن باگ و کارکرد هم دو حالت دارن:    ۱. یا جامعه بزرگ یا چند تا توسعه‌دهنده پرکار پشت‌شون هستن که اون کتابخونه رو ساپورت باگ‌هاشون رو سریع پیدا و فیکس میکن.    ۲. یکی دوتا توسعه‌دهنده دارن که این بسته رو فلان سال نوشته‌اند و به حال خودشون رها کردن و ممکنه باگ‌های بسیاری داشته باشن و هیچ‌کس هم پاسخ‌گوشون نیست.تا اینجا:stdlib 1️⃣ : 1️⃣ PyPI➰➰➰➰➰➰➰➰➰➰➰➰➰✅ پشتیبانی:        در توسعه نرم‌افزار شما باید حواس‌تون به dependency‌های اون نرم‌افزار باشه، هر چقدر برنامه شما بیشتر از بسته‌های مختلف استفاده کنه، ریسک باگ پیدا شدن در اون بیشتر هست. بالاتر گفتیم اصلا شاید یکی از کتابخونه‌هایی که نصب کردید دیگه توسعه پیدا نکنه. به مشکلات جدی بخوره و ... حالا شما دو انتخاب دارید:    ۱. خودتون برید اون کتابخونه رو مطالعه کنید و برای نرم‌افزارتون نگهداری کنید.    ۲. اون رو حذف کنید و قسمت‌هایی که به اون کتابخونه احتیاج داشتید رو باز نویسی کنید.پس در دو حالت ضرر کردید.        اما این در مورد stdlib آنچنان صدق نمیکنه؛ چرا؟ چون اولا همین که در stdlib هستن یعنی تا مدت‌های مدیدی قراره کاملا از ساپورت برخوردار باشن. ثانیا همیشه و بدون نصب یه چیز اضافه و فقط با یک import ساده شما بهشون دسترسی دارید. اما این رو هم در نظر داشته باشید که هر چقدر بیشتر از stdlib ایمپورت کنید،‌ dependencyهای شما زیاد شده اما دیگه نگرانی‌های بالا رو نخواهید داشت.تا اینجاstdlib: 2️⃣ : 1️⃣ PyPI➰➰➰➰➰➰➰➰➰➰➰➰➰✅ یک سری از کتابخونه‌ها با Cython نوشته شده‌اند (برای مثال:‌ uvloop ،httptools و asyncpg و .....) این کتابخونه‌ها نمیتونن به stdlib وارد بشوند؛  چون اگر یک کتابخانه بخواد به stdlib اضافه بشه یا با پایتون باید نوشته شده یا با زبان سی (با استفاده از C API). کاری که سایتون میکنه اینه که شما با سینتکسی بسیار شبیه به پایتون کدی رو می‌نویسید و سایتون میاد و یک کد optimize شده با زبان سی براتون generate میکنه و یک C extension برای شما می‌سازه و شما از خروجی می‌تونید به عنوان یک کتابخونه عادی پایتون استفاده کنید.        خب مشکلش کجاست؟ مشکلش اینه که سایتون هم یک بسته PyPI هست D: اگر بسته‌ای تولید شده از سایتون به stdlib اضافه بشه، اون‌وقت خود پایتون یک dependency خارجی داره و به سایتون احتیاج خواهد داشت.        اگر قرار باشه در آینده بسته‌های تولیدی از سایتون به stdlib اضافه بشن، پایتون اول باید Cython رو درون خودش embed کنه و اون رو در stdlib به رسمیت بشناسه، تا بعدش بتونیم کتابخونه‌های تولیدی سایتون رو به stdlib پایتون اضافه کنیمتا اینجا:stdlib 2️⃣ : 2️⃣ PyPI➰➰➰➰➰➰➰➰➰➰➰➰➰✅ از نظر general purpose بودن پایتون:        پایتون یک زبان (ران تایم، اکوسیستم و ...)‌ general purpose هست! یعنی روی یک موضوع مشخص تمرکزی نداره؛ اما از جهت دیگر یک زبان batteries included هم هست، یعنی با خودش یک stdlib عه general purpose داره. این استاندارد لایبرری باید یک رنج مختلفی از مشکلات رو بر طرف کنه. برای مثال ما ماژول csv داریم، ماژول json داریم، ماژول ZoneInfo داریم، ماژول tkinter هم داریم.        خب بعضی از لایبرری‌ها به طور خاص روی یک موضوع خاص تمرکز کرده‌اند، برای مثال NumPy. اضافه کردن این لایبرری به پایتون باعث میشه یک کتابخونه بزرگ و عظیم در حوزه Numeric Python به stdlib اضافه بشه که با general purpose بودن آنچنان مرتبط نیست! در ضمن اگر به stdlib اضافه بشه مشکل آپدیت شدن طبق چیزی که بالاتر گفتیم رو داره.         برخی از لایبرری ها بسیار حجیم هستن، اگه قرار بود همه ی این لایببری ها داخل standard library باشن و همراه پایتون بیان حجم فایل دانلودی پایتون بسیار بالا میرفت دیگه ۲۰ الی ۳۰ مگابایت نبود.        بیش از ۹۰٪ پکیج های موجود در PyPI بر پایه‌ی ماژول هایی که داخل standard library هستن نوشته شدن و به نوعی اون رو گسترش دادن. به طور مثال پایتون امکان فرستادن درخواست و گرفتن اون رو با ماژول socket فراهم میکنه و افراد یا گروه های مختلف بر اساس سلیقه انواع framework های تحت وب رو مینویسن.➿➿➿➿➿➿➿➿➿➿➿➿➿➿➿➿می‌بینید که از جنبه‌های مختلفی این موضوع رو بررسی کردیم و نمیشه رای قطعی داد که یا این یا اون؛ هر کدوم در جای خودش بهترین عملکرد و ویژگی‌ها رو دارن!Happy Pythoning  :)</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Wed, 09 Mar 2022 14:06:51 +0330</pubDate>
            </item>
                    <item>
                <title>چند ویدیوی خوب از آقای Raymond Hettinger</title>
                <link>https://virgool.io/@liewpl/some-talks-by-raymond-hettinger-lj2649n0wjcm</link>
                <description>بیاید یکی از core developer های پایتون رو اول بشناسیم.✔️ آقای Raymond Hettinger.یکی از Python Core Developerهای افسانه‌ای پایتون ( از سال ۲۰۰۰ به این‌ور) که:set(), frozenset(), sorted(), reversed(), enumerate(), any(), all(), zip() رو به لیست built-in ها و collections, itertools, lru_cache به استاندارد لایبری و key-functions, generator expressionsبه زبان Python و peephole optimizer, length-hint, fast sum, etc.به لیست optimizationها، اضافه کردن.ایشون تلاش‌های بسیاری هم روی دیکشنری‌ها کردن و CompactDict رو جامعه‌ پایتون به اسم RaymondDict هم میشناسه. فکر نکنم دیگه چیزی برای معرفی ایشون داشته باشیم :))ایشون در حال حاضر پایتون رو به هزاران نفر تدریس میکنن و در کار تدریس واقعا حرفه‌ای و جذاب رفتار میکنن.در این پست میخوام چند از ویدیوهای خوب ایشون رو بهتون معرفی کنم✅ موضوع Abstract Base Classes یکی از موضوع‌های بسیار کاربردی و پیشرفته برنامه‌نویسی هستن که پایتون هم ست کامل و جذابی ازشون در اختیار داره.اگه راجع‌ بهشون چیزی نمیدونید یا میخواید مثال‌های واقعی و مثال‌هایی که وقعا در محیط production ازشون استفاده شده، ببینید این ویدیو رو اصلا از دست ندید.https://www.youtube.com/watch?v=S_ipdVNSFlo✅ اگر قبلا با زبان‌های سی‌پ‌پ و یا جاوا کار کرده باشید، با super احتمالا به خوبی آشنا شدید. اما وقتی میاید در پایتون ازش استفاده کنید (خصوصا حین ارث‌بری چندگانه) متوجه میشید که super اون‌جوری که اونجا کار می‌کرده اینجا کار نمیکنه.یا حتی اگه فقط پایتون کار کرده باشید و می‌خواید اطلاعات بیشتری راجع به super بدست بیارید و ببینید در ارث‌بری یگانه و خصوصا چندگانه چجوری کار میکنه کنفرانس ایشون و live coding رو از دست ندید :)https://www.youtube.com/watch?v=xKgELVmrqfs✅ دیتاکلاس‌ها Dataclassesواژه‌ای دو قسمتی که از data و class تشکیل شده. اگر هیچ چیزی راجع بهشون نمیدونید، تدریس خیلی خوب آقای Hettinger بهتون دید خوبی از اونها میده :)https://www.youtube.com/watch?v=T-TwcmT6Rcw&amp;amp;t=1s✅ احتمالا تا الان حداقل یک class رو در کد‌هاتون نوشتید، اما می‌دونید که چه جعبه ابزار پری در نوشتن کلاس‌ها در پایتون دارید؟ آقای Hettinger در مورد «جعبه‌ابزار نوشتن کلاس‌ها در پایتون،» مثل همیشه در این ویدیو توضیحات خیلی زیبایی به همراه مثال‌های خیلی خوب دارند.https://www.youtube.com/watch?v=HTLu2DFOdTg&amp;amp;t=21s✅ راجع به Python core developers شنیدید،‌ هیچ می‌دونید چه کار هایی میکنن، روند کاری‌شون چجوره، چطور ما هم میتونیم یک python core developer بشیم؟ایشون راجع به این موضوع خیلی جذاب در این دو ویدیو صحبت میکننhttps://www.youtube.com/watch?v=voXVTjwnn-U&amp;amp;t=2shttps://www.youtube.com/watch?v=-TdrFjDJn5E✅ راجع به concurrency در پایتون چیزی نمیدونید ای اطلاعات کمی دارید؟ میخواید راه‌های مختلف این روش برنامه‌نویسی رو بدونید. ایشون در این دو ویدیو صحبت‌های خیلی خوب راجع به این موضوع دارندhttps://www.youtube.com/watch?v=9zinZmE3Ogk&amp;amp;t=1shttps://www.youtube.com/watch?v=Bv25Dwe84g0&amp;amp;t=27sموفق باشید.</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Sun, 13 Feb 2022 16:29:42 +0330</pubDate>
            </item>
                    <item>
                <title>پایتون؛ زبانی برای شرکت های مشتاق پیشرفت و performance بالا</title>
                <link>https://virgool.io/@liewpl/%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-%D8%B2%D8%A8%D8%A7%D9%86%DB%8C-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%B4%D8%B1%DA%A9%D8%AA-%D9%87%D8%A7%DB%8C-%D9%85%D8%B4%D8%AA%D8%A7%D9%82-%D9%BE%DB%8C%D8%B4%D8%B1%D9%81%D8%AA-%D9%88-performance-%D8%A8%D8%A7%D9%84%D8%A7-jc7ehvywizso</link>
                <description>چند روز پیش داشتم مقاله های اقای Brett Cannon، یکی از توسعه‌دهنده های core پایتون، رو میخوندم که رسیدم به این مقاله: https://snarky.ca/programming-language-selection-is-a-form-of-premature-optimization/ بخش هاییش رو براتون اینجا میگم.«تا حالا شنیدید که میگن پایتون برای فلان پروژه خوب نیست چون نمیتونه به اندازه کافی سریع باشه؟ من شنیدم. و این جمله کمی ناامید کننده‌س چون که بانک‌های بزرگ، یوتوب، اینستاگرام، و خییلی جاهای دیگه که نسبت به performance حساس هستن هنوز هم میان پایتون رو انتخاب میکنن و از این قضیه راضی هم هستن.»خودمون هم تا حالا بسیاار این بحث هارو شنیدیم و خوندیم و حتی خودمون هم توش شرکت کردیم که: پایتون کُنده، پایتون سرعتش خیلی کمه نرید سمتش. خوب نیست. کدوم شرکتی سرعت نمیخواد.یا حتی یک سری‌ها پا رو فراتر میگذارن که پایتون خیلی ساده‌ست و در و پیکر نداره. شما یک سری کد رو حفظ میکنید و همون هارو تکرار میکنید. شما اصلا مهارت حل مسئله یاد نمی‌گیرید و از این جور صحبت ها.یک سری‌ها هم میگن: نه شما حتما باید در شروع برنامه‌نویسی از یک زبانی مثل سی/سی‌پلاس‌پلاس شروع کنید تا عمق پیدا کنید ? (که خودمون هم می‌دونیم ۱. عمق پیدا کردن با چهار روز آموزش دیدن از اون زبان حاصل نمیشه. ۲. همون چهار روز آموزش دیدن، تازه ضرر هم می‌زنه به طرف چون زبان های مختلف، طبیعت های متفاوتی دارن و نوع تفکر در اون ها بالاخره با باقی زبان ها فرق میکنه و ۳. چرا دانشگاه های تاپ آمریکا (مثل MIT) از قول گویدو ون راسم دارن با پایتون شروع میکنن؟!)بعضی‌های دیگه هم (از امثال مدحج) میگن نه بین فلان زبان و پایتون اون یکی بهتره. چرا؟ چون سوئیچ کردن از پایتون به دیگر زبان‌ها سخته‌ (که باید ازشون سوال پرسید اولا این جمله چرا باید درست باشه؟ و ثانیا مگه ما زبان یاد میگیریم که بعدش حتما سوئیچ کنیم روی یه چیز دیگه؟ ?)اما سوال اینجاست که آیا واقعا این صحبت ها درستن؟ چندتامون (بعضاً) بخاطر این صحبت ها از پایتون ناامید شدیم و می‌خواستم بریم سراغ چیز دیگه‌ای؟ (یا حتی رفتیم؟!)از نظر آقای Brett Cannon: «اگر با توجه به تصوراتی که از قبل راجع به یک زبان دارید، که مثلا بگید فلان کنده این یکی سریع عه، یا با توجه به چیزی که بقیه میگن بیاید زبون برنامه نویسی رو انتخاب بکنید برای یک پروژه، این شانس رو از دست میدید که مثلا تیم شما همشون با فلان زبان راحت هستن، همه هم اون زبان رو به خوبی بلد و می‌تونن به خوبی اون مسئله رو حل کنن، اما شما تیم رو مجبور کردی که که با یک زبان سخت تر کار رو انجام بدن که همه میگن اون زبون سریع تره. اماااا شما وقت زیاد و هزینه گزافی رو سر این کار تلف کردید در صورتی که نیازی به این کار نبوده.»ایشون هم در این مقاله و هم در توییت‌شون: راجع به یک چرخه صحبت می‌کنن، که میگن روند کار ما اینجوریه:۱. با پایتون بنویسش۲. کد رو profile کن۳. _اگررر_ به اندازه کافی سریع نبود، الگوریتم و داده‌ساختار هات رو بهتر کن۴. باز هم _اگررر_ به اندازه کافی سریع نبود، از implementation دیگری از پایتون استفاده کن (اونی که زیاد نخواد کد رو تغییر بدی (مثلا Pyjion که اصلا لازم نیست به کد دست بزنی :)))۵. _اگررر_باززز_ هم به اندازه کافی سریع نبود:‌ کدتون پایتون‌تان را با پیوند زدن کد زبان های دیگر بهینه کنید. (language bindings)در حالی که ممکنه این قدم ها طولانی به نظر بیاد، یادتون باشه که پایتون به سمت بهروی (productivity) گرایش زیادی داره، و همین باعث شکایت های زیادی شده ? که یک نفر کاری را در یک سوم زمانی که تیم مقابلش همان چیز را با جاوا یا سی‌پلاس‌پلاس نوشته، انجام داده. و زمانی که اون تیم ورژن یک اون چیز رو تا مرحله بتا پیش برده، نسخه‌ای که با پایتون نوشته شده به ورژن ۳ رفته و کلی روی اون تست انجام شده و به بلوغ خوبی رسیده، و به اندازه کافی بهینه شده که اون نیاز رو به خوبی برطرف کنه.یک مثال کوچولو ببینیم:خب به شما گفته شده تعدادی از اعداد دنباله فیبوناچی رو چاپ کنید. چیزی که اول از همه به ذهن میرسه خوب فرمول بازگشتی دنباله هست:fib(n) = fib(n - 1) + fib(n - 2) where n = 1 -&gt; 0 and n = 2 -&gt; 1 https://en.wikipedia.org/wiki/Fibonacci_number خب میای و می‌نویسیتا چندین شماره اول اصلا حس نمیشه که این کنده. و مشکل شما حل شده و براتون کافی بوده. اما میره جلو تر و می‌بینی واقعا دیگه این کنده :(اگه این مقاله رو نخونده باشی، و صحبت های دیگران روت تاثیر گذاشته باشن : میگی نه این پایتون به درد نمی‌خوره!اما بیا طبق اون چرخه‌ای که معرفی شد پیش بریم:خب یکی از راه‌حل هایی که همین الگوریتم بازگشتی مارو سریع تر میکنه cache کردن، مقادیر محاسبه شده‌ست:این خودش سرعت رو خیلی بهبود می‌بخشه و می‌تونه آخرین قدم ما باشه و برامون کافی باشه.اما میگید نه، باز هم کندهبیاید الگوریتم رو عوض کنیم:یهو می‌بینی بووووم!! چقدر خوب بود سرعت واقعا زیاد شد. فهمش هم چقدر راحت تر از اون تابع بازگشتی شده!! این یک مثال ساده بود اما خییلی جا های دیگه میشه دیدش.بیاید چند تا از قدم هایی که ایشون به ما گفتن رو بررسی کنیم:با پایتون شروع کنید.شما بالاخره باید از یجایی شروع کنید و به لطف پایتون که طوری طراحی شده که to make you productive، شما خیلی راحت می‌تونید یه چیزی رو بنویسید و خیلی سریع به نتیجه برسید و احتمالش هم بالا هست که که اون کد به اندازه کافی سریع عه و دیگه کار شما تموم شده :))به قول آقای Andrew Godwin، نویسنده Django Channels و یکی از توسعه‌دهنده هایی که داره جنگو رو async میکنه: «خود من تا جایی که بتونم سمت async نمیرم و کار خودم و بقیه رو پیچیده نمیکنم.» خب این یعنی چی. ایشون ادامه می‌دادن، برای خیلی از شما همین جنگوعه Sync کافیه، و بعضی جاها شاید مجبور باشید که کد async بنویسید.این یعنی واقعا خیلی وقت ها اون‌ تصوری که ما از کندی داریم و اینکه مثلا باید این کد حتما حتما زیر نیم ثانیه ران بشه غلطه. یکی از مدرسان پایتون، آقای Tim Buchalka، توی دوره‌ای که برای پایتون دارن یه مثال قشنگی رو میزنن.ایشون میگن این کد رو ببینید:بیاید فرض کنیم کد بالا قرار توی دو میلی ثانیه انجام میشه،و کد زیر فرض کنیم توی یک میلی ثانیه انجام میشه.خب فرقش چیه؟گفت: فرض کنید کد شما داره توی یک جت جنگنده اجرا میشه و اون جت در هر ثانیه ۲۳۰۰ متر میره.خب هر میلی ثانیه برای این جت چند متر میشه؟ میشه ۲.۳ متر. اینجاست که مهم میشه از کد پایینی استفاده کنیم تا کد بالایی :)الگوریتم و داده‌ساختارتون رو بهتر کنید.این کد رو ببینید:خب فرقش چیه؟ نتایج که فرقی نمی‌کنه!!!!اماااا خیلی فرق میکنه: در واقع membership testing در داده ساختار هایی مثل list و tuple (که ایندکس دارن و ترتیب دارن) به صورتی خطی هست، یعنی پایتون یکی یکی به ترتیب ازشون آیتم میگیره و چک میکنه. امااا در چیزی مثل set، این قضیه برقرار نیست و چون از hash map ها استفاده شده خیییلی سریع تر در اون المنت ها پیدا میشن.فرقی بین چک کردن ۱ توی لیست و ست نیست، مثلا میشه 0.0001 ثانیه، اما تفاوت جایی هست که میای یه آیتم از آخر رو می‌خوای چک کنی. در این مثال برای لیست مثلا میشه 0.01 ثانیه اما برای ست آچنان فرقی نمیکنه و تقریبا همون 0.0001 بدست میاد.دیدید! اینجاست که لینوس توزوالدز میگه:&quot;Bad programmers worry about the code. Good programmers worry about data structures and their relationships.&quot;از یک پیاده‌سازی (implementation) دیگه پایتون استفاده کنید.خیلی هامون راجع به مفسر های دیگه‌ای که دارن توسعه داده میشن خبر داریم. اون‌هایی که هر کدوم با هدف خاصی نوشته میشن و دارن پیشرفت میکنن (هر چند بعضی‌ها شون دیگه راکد شدن.)چیزی که مهمه اینکه مفسری رو بر ندارید که بخواید کدتون رو خییلی عوض کنید. چیزی رو انتخاب کنید که کمتر زحمت رو براتون داشته باشه. برای مثال:۱.  PyPy۲. Numba ۳. mypyc۴. Pyjion باز هم مثل قبل شما باید چند تا بررسی کنید و بهترین رو انتخاب کنید (برای مثال اگه منطقه های داغ کد شما (اونجایی که زمان زیادی میگیره) با اعداد سر و کار ندارن Numba گزینه خوبی نخواهد بود.)از Language Binding ها استفاده کنید.به قول ایشون: «این پست به دلیل توییتی در مورد استفاده از Rust برای سرعت بخشیدن به برخی از کدهای پایتون نوشته شد. به لطف تاریخچه طولانی پایتون، که می‌تونی خیلی راحت به دیگر زبان ها وصل بشه یا دیگر زبان ها بهش وصل بشن (glue code)، راه های بی شماری برای فراخوانی زبان های دیگر که ممکن است بتوانند سریعتر از خود پایتون کار کنند، به دست آمده است»:۱. PyO3 for Rust۲. HPy for C۳. pybind11 for C++۴. Cython for C...و این یک لیست بلند بالایی واسه دیگر زبان ها و ابزار هاست.تفاوت اصلی این روش با روش قبلی اینکه، اینجا دیگه شما باید کمی کد نویسی کنید. اما اگر نیاز های performance شما دیگه خییییلی مهم و حیاتی عه، این گزینه راحت میتونه نیاز شما رو برطرف کنه. می‌تونید این راه رو شروع کنید، و شاید آرام آرام در طول یک زمانی ببینید کل کد های پایتونی خود یا عوض کرده‌اید اما مهم‌ترین مسئله‌ای که وجود داره اینکه:«الگوریتم ها و طراحی‌های اون برنامه رو قبلا تایید کردید و ابزارهای زیادی هم برای تست اون کد دارید که می‌تونید استفاده کنید.»یکی از مهم‌ترین بند هایی که در این مقاله هست اینه:Consider optimizing for developer time, not computation costs.به قول ایشون: «اینایی که زبان برنامه نویسی رو براساس پرفورمنسش انتخاب میکنن، معمولا اونایی هستن که فکر میکنن هزینه سرور و اینا از بهینه کردن زمان توسعه مهمتره. ولی با توجه به این که هزینه برنامه نویس ها گرونه، من (نویسنده) فک نمیکنم همیشه اینجوری باشه.اگر شما به هزینه سرویس ابری‌تون نگاه کنید و بعد به تعداد برنامه نویس هایی که دارین حقوق میدید توجه کنید، حدس من اینه که اگر زبانی رو انتخاب کنید که به تعداد برنامه نویس های کمتری نیاز داشته باشه، شما میتونید با کاهش هزینه حقوق برنامه نویس ها، بیشتر از کاهش هزینه سرور، در هزینه هاتون صرفه جویی کنید.»از قول یه دوست: «اگه وقت کامپیوتر ها برای شما از وقت برنامه‌نویس ها ارزش‌مند تره برید هم پول بیشتری به برنامه‌نویس هاتون بدید و هم وقت خیلی بیشتری رو صرف توسعه یک کاری بکنید. اما در دنیای واقعی مسئله اینکه وقت برنامه نویس چقدر گرفته میشه خیلی مهم تره، اگه برید قیمت هارو مقایسه کنید می‌بینید که بالاتر بردن قیمت سرویس ابری خیییلی به صرفه‌تر از پول بیشتر دادن به برنامه نویس عه.»نقل قول از یه دوست دیگه:‌«نمونه چنین چیزی شرکت shopify هست که استکش روبی هست. روبی هم مثل پایتون ساده هست ولی ملت میگن اسکیل نمیشه، هزینه سرورش بالاس و اگر شرکتها به جای انتخابش از زبون های بهینه تر مثل جاوا، سی یا گو استفاده کنن، میتونن در هزینه سرور و در نهایت هزینه های شرکت صرفه جویی کنن. ولی خب این شرکت دقیقا نشون داده که این هزینه سرور اونچنان که ادعا میشه زیاد نیست و از هزینه و وقت برنامه نویس ارزش کمتری داره. در نتیجه هزینه سرورهای این شرکت در مقابل درامدش تقریبا هیچه.»همه این حرفا به این معنی عه که برای بعضی شرکت‌ها براشون کم کردن هر cycle عه cpu واقعا ارزش داره،‌ اما خب اون‌ها در عمل دارن دیتاسنتر می‌نویسن. اما شمایی که اصلا کاری به این چیز نداری، یه چرتکه بندازید ببینید پایین آوردن productivity برنامه‌نویس های تیم‌تون، به اسم اینکه «خب قراره سریع تر محاسبات انجام بشه،» به صرفه‌تره یا اینکه بیاید چهار تا سرور به سرور هاتون اضافه کنید؟</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Mon, 03 Jan 2022 12:58:33 +0330</pubDate>
            </item>
                    <item>
                <title>قرار است سرعت پایتون ۵ برابر شود :)</title>
                <link>https://virgool.io/@liewpl/cpython-five-times-faster-p5jve4zzywog</link>
                <description>تا کنون موفقیت های زیادی رو از زبان پایتون دیدیم و شنیدیم. زمانی که گویدو ون راسم «دیکتاتور خیرخواهجاویدان» بود بیشتر دوست داشت که سی‌پایتون ساده بمونه حتی در صورتی که کمتر بهینه باشه. بعد از بازنشستگی از این سمت هم، هنوز این تفکر بین توسعه‌دهنده‌های سی‌پایتون بود. در یکی از خطوط راهنمای (Guide line) توسعه سی‌پایتون خوندم: سورس کد سی‌پایتون (خصوصا اگر به زبان سی باشه) باید ساده و قابل فهم باشه، حتی کامنت‌ها و داکیومنتیشنی که برای اون کد تولید میشه باید ساده باشه و حتی کلمات اون باید در حد فهم یکی دانشجوی کارشناسی رشته کامپیوتر (undergraduated student) باشه. چون پایتون داره توسط یک جامعه بزرگ پیشرفت می‌کنه و سورس‌کد نباید جوری باشه که به شخص خاصی وابسته بمونه و کس دیگه‌ای نتونه اون رو بفهمه و بهترش کنه.از این رو تا الان که چند وقتی از منتشر شدن پایتون 3.10 میگذره، تمرکز و توجه توسعه‌دهنده‌های سی‌پایتون روی ویژگی های جدید و افزودن قابلیت های جدید به پایتون بوده و کمتر به بهینه‌تر کردن کد و سریع‌تر کردن اون پرداخته شده (به «تر» ها دقت کنید.) البته این به این معنی نیست که چیزی که الان داریم بهینه نیست، صد البته که هست، بحث تمرکز کردن فقط روی بهینگی هست، وگرنه برای مثال دیکشنری ها در پایتون از چیز‌هایی اند که وقت و تلاش بسیاری برای بهینه کردنشون صورت گرفته و اصطاحا میگنdictionary lookups are super fast.یکی از کسایی که پروژه تمرکز روی بهینه کردن سی‌پایتون رو استارت زد آقای مارک شنون Mark Shannon بود که رساله دکتری‌اش در مورد ساخت ماشین های مجازی با کارایی بالا برای زبان های پویا  ( The construction of high-performance virtual machines for dynamic languages ) هست. پروژه‌ای که ایشون روش کار می‌کردن HotPy نام داشت. این پروژه به ورژن دو رفت و HotPy 2 تولید یک کامپایلر JIT رو نوید میداد.بعد از بازنشسته شدن گویدو ون راسم از شرکت دراپ‌باکس، او پس از گذروندن مدتی متوجه شد که نمیتونه توی خونه بمونه و باید کاری انجام بده، سپس او تصمیم گرفت که بره مایکروسافت و اونجا کار کنه. که گویدو راجع بهش میگه:&quot;I got bored sitting at home while retired. I applied at Microsoft and got hired. I was given freedom to pick a project. I chose to go back to my roots. This is Microsoft&#x27;s way of giving back to Python.&quot;سر انجام، گویدو ون راسم، مارک شَنون و اریک اسنو (Eric Snow) تیم کوچکی رو تشکیل دادن (که گویدو میگه ممکنه بزرگ تر هم بشه) که فقط می‌خوان روی بهینه‌تر کردن سی‌پایتون و سریع‌تر کردن اون کار بکنن.این تیم یک ریپازیتوری داره به اسم Faster CPython که یک فورک از سی‌پایتون و دو ریپازیتوری دیگه در اون وجود داره که پیشنهاد می‌کنم حتما مطالعه کنید. https://github.com/faster-cpython تا الان خود گویدو ون راسم گفته که قراره سرعت سی‌پایتون در ورژن 3.11 دو برابر بشه.جدای از این‌ها آقای مارک شَنون، خودش یک ریپازیتوری به اسم Faster Cpython داره که در نقشه راهی که اون ترسیم کرده ( که پیشنهاد میدم این رو هم حتما بخونید ) قراره سرعت پایتون طی چهار انتشار دیگه‌، ۵ برابر بشه. 1.5 ** 4 = 5.0625 https://github.com/markshannon/faster-cpython یکی از مهم‌ترین فاکتور هایی که این تیم در نظر دارن، سازگاری با ورژن های گذشته پایتون هست. از اونجایی که پایتون بین دانشمندان بسیار محبوبه و پروژه های خییلی زیادی با پایتون در سراسر دنیا ( با تکیه بر همین پایتونی که الان داریم ) دارن کار می‌کنن، اون‌ها نباید این گستردگی رو فدای سرعت بکنن و گویدو گفته بسیار روی این موضوع سخت‌گیر هستیم.آقای مارک شنون در این باره میگه:در مورد این سخت‌گیری باید از گویدو بپرسید، اما فکر میکنم یکی از دلایل این سخت‌گیری اینست که محبوبیت پایتون در یادگیری ماشین در چند سال اخیر افزایش چشم‌گیری داشته و بدین معنی‌ست که نباید سریع‌تر کردن پایتون، به پایداری اون و کد هایی که الان داره کار می‌کنه لطمه بزنه.یکی از مثال های بازر این تغییر زبان، رفتن پایتون از ورژن دو به ورژن ۳ بود که برای بسیاری این مهاجرت دردناک بود.منابع:گویدو ون راسم و مارک شنون با مایکل کندی، در پادکست Talk python to me.نسخه صوتی https://talkpython.fm/episodes/show/339/making-python-faster-with-guido-and-mark نسخه ویدیوییmaking-python-faster-with-guido-and-matk-YouTubeGuido van Rossum aiming to make CPython 2x faster in 3.11Faster Python: Mark Shannon, author of newly endorsed plan, speaks to The RegisterThe construction of high-performance virtual machines for dynamic languagesشاد باشید :)</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Tue, 07 Dec 2021 19:13:33 +0330</pubDate>
            </item>
                    <item>
                <title>ساختار یک بسته کد منبع ( source package )</title>
                <link>https://virgool.io/@liewpl/structureofsourcepackgeindebian-kbjsvrijidej</link>
                <description>چه چیزی همه چیزه؟ خب شاید بخوایم جمله ای شبیه به جمله‌ی عبید زاکانی بگیم که میگه: «همه چیز همگان دانند، و همگان هنوز از مادر زاده نشده اند.» اما خب، سوال ما اینه چه چیزی همه چیزه نه اینکه چه چیز یا کسی همه چیز رو میدونه! این سوال در دنیای توزیع &quot;دبیان گنو/لینوکس&quot; جواب داره: بسته های منبع ( source packages. ) هر چیزی در دبیان از یک بسته منبع میاد، و چیزی که DM ها ( Debian Maintainers ) در واقع روش دارن فعالیت میکنن، همین source package ها هستن. خب فکر کنم دیگه اهمیت‌شون رو فهمیدید بریم که یه بررسی روشون داشته باشیم.فرمتیک بسته کد منبع معمولا شامل سه فایل با پسوند های .dsc, .orig.tar.gz and .debian.tar.xz (or .diff.gz)هستن. اونا امکان ساخت بسته های باینری رو به ما میدن که در این مقاله راجع بهشون صحبت کردم. فایل .dsc ( کنترل منبع دبیان debian source control ) یک فایل متنی کوتاه حاوی یک سرصفحه RFC 2822 است (درست مانند کنترل فایل که در مقاله اطلاعات همراه با بسته های باینری راجع بهش صحبت کردم) که بسته منبع و سایر فایل های مربوط بهش رو توضیح میده. این فایل توسط نگهدارنده ( maintainer ) آن امضا شده که اصالت اون رو تضمین می کند.برای توضیح بهتر ما به یکی از این بسته های نیاز داریم برای دریافت یکی از بسته ها  مثل تصویر زیر عمل کنید:این بسته کد منبع مربوط به توزیعی رو برامون دانلود میکنه که در source.list ما آدرس دهی شده باشه ( ... deb-src ) و خودش هم اولش نوشته که این بسته توسط سیستم کنترل ورژن Git داره مدیریت میشه و در این آدرس هست و از این دستور استفاده کنید تا آخرین نسخه رو تغییرات رو دریافت کنید. سه خط پایین هم توسط dpkg انجام شدند که نشون میده به صورت خودکار داره برامون استخراجش میکنهو چیزی که ما داریم این خواهد بود:۴ خط آخرحالا بریم ببینیم توی فایل کنترل منبع دبیان چی هست:همین‌طور که میبینید header های متفاوتی در این فایل وجود داره که اطلاعات مهمی رو در موردش ذکر کرده. توجه کنید که این بسته کد منبع هم پیشنیاز هایی داره :) در هدر Build-Depends چیز هایی ذکر شدند که کاملا متمایز از بسته باینری‌اش اند، زیرا آنها ابزارهای مورد نیاز برای کامپایل نرم افزار مورد نظر و ساخت بسته باینری آن را نشون می دهند.در اینجا لازم به ذکر است که هیچ تناسبی بین نام بسته منبع و بسته (های) باینری که ایجاد می کند وجود ندارد. باید بدانیم که هر بسته منبع ممکنه چندین بسته باینری تولید کنه و به همین دلیل عه که فایل dsc. دارای فیلد Source و Binary است که صریح بسته منبع را نامگذاری کرده و لیست بسته های باینری را که تولید می کند ذخیره می کند.فرمت های مختلف بسته منبعدر ابتدا تنها یک قالب بسته منبع وجود داشت. این فرمت 1.0 بود که یک آرشیو .orig.tar.gz را به یک وصله &quot;diff.gz &quot;debianization patch متصل میکرد.از زمان Debian 6 Squeeze ، توسعه دهندگان Debian توانستند که از فرمت های جدیدی استفاده کنند که بسیاری از مشکلات قالب قدیمی قبلی را برطرف می کند. فرمت 3.0 (لحاف quilte) می تواند چندین بایگانی بالادستی ( upstream ) را در یک بسته منبع مختلف ترکیب کند: علاوه بر orig.tar.gz. معمول ، بایگانی های تکمیلی .orig-component.tar.gz را می توان گنجاند. این با نرم افزارهایی که در چندین جزء بالادستی توزیع شده اند اما برای آنها یک بسته منبع واحد مورد نظر است مفید است. این بایگانی ها همچنین می توانند با xz به جای gzip فشرده شوند، که باعث ذخیره فضای دیسک و منابع شبکه می شود. در نهایت ، وصله یکپارچه ، .diff.gz با بایگانی .debian.tar.xz جایگزین دستورالعمل تدوین و مجموعه ای از وصله های بالادستی که توسط نگهدارنده بسته کمک می شود ، جایگزین می شود.فایل orig.tar.gz. آرشیوی هست که شامل سورس کدی است که توسط توسعه دهنده اصلی ارائه شده است.از نگهدارندگان بسته دبیان ( Debian package maintainers ) خواسته می شود که این آرشیو را تغییر ندهند تا بتوانند به راحتی منشاء و یکپارچگی فایل را (با مقایسه ساده با check sum ) بررسی کرده و به خواسته های برخی نویسندگان احترام بگذارند.آرشیو debian.tar.xz. شامل همه تغییرات ایجاد شده توسط نگهدارنده دبیان است ، به ویژه افزودن یک پوشه دبیان حاوی دستورالعمل های مربوط به ساخت یک بسته باینری از آن.استفاده در دبیانبسته منبع پایه همه چیز در دبیان است. همه بسته های دبیان از یک بسته منبع تهیه می شوند و هرگونه اصلاح در بسته دبیان نتیجه تغییراتی است که در بسته منبع ایجاد شده است. نگهدارندگان دبیان با بسته منبع کار می کنند ، با این حال ، عواقب اقدامات خود را بر روی بسته های باینری می دانند. ثمرات کار آنها در بسته های اصلی موجود از دبیان یافت می شود.وقتی نسخه جدیدی از یک بسته (بسته منبع و یک یا چند بسته باینری) روی سرور دبیان وارد می شود ، بسته منبع مهمترین چیز است. سپس توسط شبکه ای از ماشینهای معماری مختلف ( architecture like: amd64, arm64, ... )  برای کامپایل بر روی معماری های مختلف پشتیبانی شده توسط دبیان مورد استفاده قرار می گیرد.https://buildd.debian.org/خیلی خوب این هم از این. امیدوارم این اطلاعات بدردتون خورده باشه. این آخرین قسمت از مجموعه سیستم بسته بندی: ابزارها و اصول اساسی بود. در سری بعدی رشته مقالات میریم سراغ یکی از قدرتمندترین ابزار های مدیریت بسته به اسم APT.شاد باشید :)</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Tue, 21 Sep 2021 15:42:10 +0430</pubDate>
            </item>
                    <item>
                <title>جستجو بین ۶۰۰۰۰ بسته در دبیان</title>
                <link>https://virgool.io/@liewpl/searchin60thpkgs-vejhy8u1tq91</link>
                <description>نصب و استفاده از سیستم عاملی که ۶۰۰۰۰ بسته قابل نصب و استفاده برای آدم داره خیلی جذابه. مخازن دبیان تقریبا میشه به جرعت گفت بزرگ ترینِ مخازن بین توزیع های دیگه هستند. دبیان تقریبا برای هر کاری کمِ کم یه بسته رو داره ( که توسط بزرگ ترین سرمایه دنیای نرم افزار متن باز و آزاد، توسعه دهنده های داوطلب و گروه ها نرم افزاری از همه جای دنیا نوشته شدن. ) اما پیدا کردن بسته ای که به دردمون بخوره از بین ۶۰۰۰۰ تا بسته میتونه خیلی سخت باشه!! سخت تر اینکه این بسته خاص، خیلی مشهور نباشه که بشه مثلا با یه سرچ ساده توی اینترنت پیداش کرد و غیره و ذالک.نبود راه های مناسب و قوی برای جستجو بین بسته ها ( و پیدا کردن ابزاری که مورد نیازه ) از بین این همه بسته یکی از مشکلاتی بوده که در گذشته وجود داشته و خوشبختانه این مشکل به کلی بر طرف شده و ابزار های قوی و بسیار خوبی برای این کار توسعه داده شدن :)بی اهمیت ترین روش جستجویی که وجود داره، جستجو برای اسم دقیق یه بسته‌ست :| یعنی اگر apt show packageجواب بده، خب اون بسته وجود داره و میشه ازش استفاده کرد. اما متاسفانه در این روش یا باید نام کامل بسته رو از قبل بدونید یا اینکه حدس بزنید که همیشه ممکن نیست!یک الگوی جستجوی کمی موفق تر اینکه بیایم یک جستجو plain-text رو بر اسم بسته ها اعمال کنیم ( منظور از این جستجو plain-text این هست که از regular expressions برای داده متنی استفاده میشه مثلا موقع جستجو بگیم که کلمه lib یا کلمه python اول اسم بسته باشه و یا اصطلاحا keyword search انجام بدیم ) که البته خیلی محدوده. اگر بخواهیم باز هم قدرت سرچ‌مون رو بیشتر کنیم میایم و این جستجوی plain-text رو روی توضیحات بسته ( description ) که در کنترل فایل اون بسته هست هم اعمال کنیم. چون این توضیحات دارای کلمات بیشتر هستن پس جستجو ما موفق تر خواهد بود. پس گام اول ما جستجوی کلمات کلیدی ( keyword search ) خواهد بودجستجو کلمات کلیدیاز اونجایی که هر بسته کم و بیش توضیحاتی رو با خودش همراه داره این الگوریتم جستجو معمولا مفید واقع میشه و ما رو به بسته های مورد نیازمون میرسونه! :) دو ابزارِ apt-cache و axi-cache برای این نوع جستجو ساخته شدن!دستور apt-cacheاین دستور میتونه اطلاعات بسیاری رو از دیتابیس درونی APT برای ما جستجو و نمایان کنه. این اطلاعات نوعی حافظه کش ( معادل اش پنهان میشه cache ) هستن که از منابع مختلفی که در sources.list نام برده شدن، جمع آوری میشن. این جمع آوری زمانی اتفاق میوفته که شما دستور apt update رو اجرا میکنید.این دستور میتونه یک جستجو بر مبنای کلمات کلیدی برای ما انجام بده. فرمت جستجو هم به اینگونه است:apt-cache search keywordاین دستور همچنین میتونه هدر ( header ) های بسته ها رو هم با دستور apt-cache show package به ما نشون بده. این دستور همون کنترل فایل رو برای ما میخونه توجه کنید که دستور های:apt search, apt show, aptitude search, aptitude show هم یکسان کار میکنند.دستور apt-cache کاربرد های بسیار دیگه ای هم داره که معروف ترین هاشون در تصویر زیر هستنبرای مثال apt-cache search xserver-xorg-video این نتایج رو داره:برای اطلاعات بیشتر و کامل تر به منوآل پیج ( man page ) این دستور مراجعه کنید :‌ man apt-cacheدستور axi-cacheابزار apt-cache یک ابزار جستجوی خیلی ابتدایی هست. اساسا تنها کاری که این بسته برای جستجو انجام میشه اینکه بر روی توضیحات و اسامی پکیج ها یک grep انجام میده و اون هایی که مچ ( match ) شدن رو به ما بر می‌گردونه. این دستور بعضی وقت ها یا نتایج بسیاری رو برامون میاره یا هیچی پیدا نمیکنه‌ :(اما دستور axi-cache search term نتایج خیلی بهتری رو مرتب شده بر اساس میزان ارتباط نتایج با جستجوی شما رو ارائه میکنه. این دستور از موتور جستجوی Xapian که جزئی از apt-xapian-index هست استفاده میکنه! این دستور از tag های بسته ها ( این تگ ها رو در ادامه به طور مفصل بررسی خواهیم کرد ) اطلاع داره و در چند میلی ثانیه نتایج رو برمی‌گردونه ( دیگه چی از این بهتر :)) )برای جستجو های پیچیده تر و بهتر ابزار قوی تر هم نیاز هست، اینجاست باید از aptitude افسانه‌ای رو نمایی کرد. aptitude به شما این اجازه رو میده که جستجو هایی بر پایه عبارات منطقی ( logial expression ) بر روی فیلد های meta-information بسته ها انجام بدید ( همان فایل افسانه‌ای که در این مقاله در موردش صحبت کردیم :) ) برای نصب این ابزار:$ sudo apt install aptitude --install-suggestsاول یک مثال بزنیم و بعدش راجع به این عبارات منطقی صحبت کنیم :جستجوی ما بسته هایی رو برگردونده که در توضیحات‌شون ( description ) کلمه video وجود داشته و تگ use::storing رو داشته اند.حالا بیاید تا این عبارات منطقی رو یاد بگیریم ( اینجا من دونه دونه عباراتی که میشه استفاده کرد رو با یک مثال به شما نشون میدم ) :?not(pattern), !patternاین عبارت هر چیزی که بهش پاس بدید رو نفی و یا منفی میکنه مثال:نگاه کنید ما تمام بسته هایی رو الان داریم که هیچ کدوم از حروف a تا w در اون ها نیست و همینطور که میبینید این عبارات میتونن از regular expressions پشتیبانی کنن پس اگه بلد هستید میتونید حرفه ای تر سرچ کنید.?action(action), ~aactionبسته هایی رو انتخاب کنید که به عنوان action علامت گذاری شدن.این اکشن ها : install, upgrade, downgrade, remove, hold, و یا keep هستن. توجه کنید که این عبارت فقط بسته هایی رو انتخاب میکنه که برای این کار ها انتخاب شده باشن و نه اینکه امکان این هارو داشته باشن، برای مثال upgrade اونهایی رو نشون میده که شما برای بروزرسانی انتخاب کردید و نه اون هایی که میش بروزرسانی شون کرد ( برای اینکار از upgradable? باید استفاده کنید. )این ها بسته هایی اند که برای حذف شدن انتخاب شدن چون در قسمت autoremove هستن.?and(pattern1, pattern2), pattern1 pattern2همین‌طور که از اسمش بر میاد، عملگر and بررسی میکنه که ایا هر دو برقرار اند یا خیر.توی این مثال تنها بسته ای که توی اسمش ( n~ عبارتی هست که چک میکنه آرگومانی که میگیره آیا توی اسم بسته هست یا نه ) هم obs باشه و هم studio?or(pattern1, pattern2), pattern1 | pattern2  باز هم همینطور که از اسم بر میاد این عملگر میگه یا این یا اون یا هر دوش :)این کار همه بسته هایی که هستن رو نشون میده :) اما تعجب نکنید چون بسته های مجازی رو هم نشون میده این عدد هست.تعداد کل بسته های قابل نصب ( که الان در کش سیستم من هستن ):?all-versions(pattern); ?any-version(pattern)باز هم اسامی این عبارات گویای همه چیز هستن، all-versions میاد چک میکنه که بسته ای تمامی ورژن هاش این الگویی که بهش دادید براشون صدق میکنه یا نه. با این عبارت aptitude ورژن های بسته رو جدا جدا و پشت سر هم تست میکنه؛ نکته قابل توجه هم اینکه بسته هایی که ورژن ندارن، مثل بسته های مجازی virtual package همیشه توسط این عبارت تایید و برگردانده میشن!مثال رو نگاه کنید بسته اولی یک بسته معمولی هست اما دومی که یک بسته مجازی هست ( اون v رو بقلش نگاه کنید ) هم برگردانده شده! اما any-version بسته هایی رو نشون میده که حداقل یکی از ورژن هاش با الگو صدق کنه! ?architecture(architecture-spec), ~rarchitecture-specبسته هایی را برمیگرداند که برای معماری architecture هستن، برای مثال “architecture(amd64)?” بسته هایی که برای این معماری هستن رو نشون میده اما &quot;architecture(all)?” بسته هایی رو بر میگردونه که تمام معماری ها رو ساپورت میکنن:?archive(archive), ~Aarchiveبسته هایی رو انتخاب میکنه که در آرشیوی که بهش دادید ( برای مثال “archive(testing)?”  بسته هایی که در آرشیو تستینگ قرار دارن رو انتخاب میکنه ) وجود دارن.?automatic, ~Mاین دستور بسته هایی که به صورت خودکار نصب شدن رو نشون میده، موقع نصب یک بسته ممکنه که APT برای اون بسته ایی رو نصب کنه، بسته هایی که در فیلد پیشنیاز ها، قید شدن اما روی سیستم نیستن، یا بسته های فیلد recommends. این به شما کمک میکنه که این بسته ها رو پیدا کنید.بسته های که هنگام نصب libreoffice به صورت خودکار نصب شدن و در اسمشون libreoffice-help وجود داره?broken, ~bاین دستور بسته هایی رو برای شما میاره که خراب شدن، حالا یا پیش نیازشون نیست، یا پیش-پیشنیازشون نیست و یا تعارضی با بسته های دیگر دارن.?broken-depType, ~BdepTypeعبارت قبلی یه عبارت کلی هست و همه بسته های خراب رو نشون میده. حالا تصور کنید من در یک موقعیت خاص میخوام فقط بسته های خرابی رو پیدا کنم که مثلا فیلد recommends‌شون یه مشکلی داره یا مثال فیلد pre-depends. اما عبارت broken-deptype? برای اینکار به کمک ما میاد!در این جستجو ما بسته هایی که فیلد recommends شون یه مشکلی داره و تگ devel::editor هم دارن!?conflicts(pattern), ~Cpatternبسته هایی رو پیدا میکنه که با بسته هایی که با الگوی داده شده همخوانی دارن، تعارض ایجاد میکنناینجا بسته هایی رو پیدا کردیم که با بسته هایی که این فیلد رو در کنترل فایل خودشون دارنMaintainer: Debian Multimedia Maintainers &lt;debian-multimedia@lists.debian.org&gt;تعارض ایجاد میکنن!?config-files, ~cاین یه عبارت جالبه. در دبیان میتونیم بسته ها رو به دو صورت حذف کنیم، اول اینکه با دستور apt remove حذفشون کنیم، این حذف کردن صرفا فایل های خود بسته رو حذف میکنه اما یک سری فایل های meta-info از پکیج روی سیستم باقی میمونن، در این مقاله کامل راجع بهشون صحبت کردم. اما حالت دوم اینکه تمام چیز هایی که به فایل مربوط میشه رو با دستور apt purge حذف و به اصطلاح complete removal انجام بدیم. حالا بیاد فرض کنیم ما چندین بسته رو از سیستم صرفا remove کردیم و میخوایم ببینیم چه بسته هایی اینجور حذف شدن . اینجاست که از این عبارت استفاده میکنیم.من قبلا این بسته رو حذف کرده بودم و می‌بینید که برام برگردانده!?depType(pattern), ~D[depType:]patternاین دستور یکی از دستور هایی هست که خیلی دوستش دارم، بسیار قدرتمنده و میشه خوب ازش استفاده کرد. این دستور رو با مثال توضیح میدم،‌ فرض کنیم که میخواهیم بسته هایی رو پیدا کنیم که xserver-xorg-video-radeon یکی از پیشنیاز هاشون هست، خب میایم و اینجور ازش استفاده میکنیم: (در حالت کوتاه دستوری اگر جلو D چیزی ننویسیم به صورت پیش فرض depends رو جستجو میکنه)این عبارت قدرتمند از تمامی فیلد هایی زیر پشتیبانی میکنه:“depends”, “predepends”,  “recommends”, “suggests”,  “breaks”,  “conflicts”, “replaces” و همچنین providesاگر از provides استفاده کنید،‌دستور بسته های ارائه شده ( provides ) رو با الگوی ( pattern ) داده شده مچ تطبیق میده و بسته ای که اون رو ارائه میکنه رو بر میگردونه:برای مثال نتایج برگردانده شده بسته هایی اند که در فیلد provides شون mail-transport-agent رو دارا هستن :?description(description), ~ddescriptionبسته هایی رو پیدا میکنه که در توضیحات اون ها description وجود داشته باشه و نکته اینکه جستجو با این عبارت به صورت regex هست :) خب فرض کنید من با زبان perl کار میکنم و میخوام یک ادیتور پیدا کنم، خب از تگ devel::editor استفاده میکنم و بین ادیتور هایی جستجو میکنم که در توضیحاتشون کلمه perl بکار رفته باشه. حالا فرض کنیم دنبال یک IDE میگردیم خب خیلی ساده‌ست فقط از تگ devel::ide باید استفاده کنیم:در قسمت توضیحات از Perl هم صحبت شده?essential, ~Eبسته های essential رو انتخاب میکند. این بسته ها آن هایی هستن که در کنترل فایل آنها فیلد Essential: yes وجود داشته باشد:?installed, ~iبسته هایی رو انتخاب میکنه که در سیستم نصب شده اند:?maintainer(maintainer), ~mmaintainerبسته هایی رو انتخاب میکنه که در فیلد maintainer شون اون چیزی که بهش پاس دادید وجود داشته باشه ، و مثل دستور d~ از regex استفاده میکنه:?multiarch(multiarch)بسته هایی رو انتخاب میکنه که قابلیت پشتیبانی از چند معماری رو دارن، برای مثال:این بحث رو بهتره راجع بهش جستجو کنید تا متوجه بشید که آیا بسته هایی از معماری X در دبیان میتونن در معماری Y نصب بشن و چگونه میشه این کار رو کرد،‌ به عنوان یک مثال دیگه multiarch(none)?این دستور بسته هایی رو انتخاب میکنه که قابلیت پشتیبانی از چند معماری رو ندارن. دبیان سیستم عاملی هست که طیف بسیار وسیعی از معماری هارو پشتیبانی میکنه و یکی از ویژگی های قدرتمند این سیستم عامل هست.?name(name), ~nnameبسته هایی رو انتخاب میکنه در اسم شون با regex چیزی مچ باشه:?obsolete, ~oبسته های نصب شده ای رو انتخاب میکنه که دیگر از هیچ یک از آرشیو های دبیان قابل دانلود نیستن?origin(origin), ~Ooriginبسته هایی رو انتخاب میکنه که origin اون ها با origin داده شده و با regex مطابقت کنه، برای مثال برای اینکه بخواهیم بسته هایی رو پیدا کنیم که از دبیان نیستن و اصطلاحا غیررسمی اند و روی سیستم نصب هستن اینجور مینویسیم:!?origin(debian)البته اگه این دستور رو بنویسید که بسته هاب رو سیستم شما نباشه که از دبیان نباشه، تمام بسته های مجازی رو بر میگردونه :|?provides(pattern), ~Ppatternاین دستور تمام بسته هایی رو برمیگردونه که بسته ای که بهش میدید رو ارائه ( provide ) میکنن?priority(priority), ~ppriorityبسته هایی رو پیدا میکنه که یکی از اولویت های :‌ extra, important, optional, required, standardرو دارا هستن.?tag(tag), ~Gtagو می رسیم به یکی از مهم ترین عبارات و قوی ترین هاشون. بله تگ های بسته هااین تگ های برای مرتب کردن بسته ها بکار میرن و یکی از بهترین ابتکار ها برای مرتب کردن و جستجو بین اون ها هستن. برای اینکه از این تگ ها به خوبی استفاده کنید اول اول اول باید manual page مربوط به بسته debtags رو مطالعه کنید. بعد از اینکه با خود این بسته و دستور هاش آشنا شدید، اول این کار رو بکنید:$ debtags tagcat &gt; AllDebTagsاین دستور تمام تگ هایی که برای بسته ها استفاده شدن رو بهتون میده. بریم یه سر به خودش بزنیم:اولین خط هاd این فایل رو نگاه کنید. اول بگم که فایل خیلی بلندی هست :) دوم اینکه تگ ها دو قسمت دارن یکی صورت ( Facet ) و دوم خود تگ، نحوه استفاده ازشون هم اینطور هست که توی خط ۶ می‌بینید. ابتدا صورت رو وارد میکنیم و با دو تا : خود تگ رو جلوش نام میبریم، بعضی وقت ها هم مثل همون خط ۶ باز هم از : استفاده میشه.برای اینکه با تگ ها اشنا بشید، از هر Document viewer یا text editor ی که استفاده میکنید، به قسمت find برید و همون کلمه Facet رو جستجو کنید، این کار برای اینکه با هر نتیجه بعدی شما به سری بعدی تگ ها میرید :)حالا چند تا مثال با هم ببینیم.فرض کنید میخواهیم ببینیم که چه ابزار های monitoring روی سیستم ما نصب هست خب خیلی راحت از تگ admin::monitoring و از i~ برای فیلتر کردن بسته های نصب شده استفاده میکنیم:یا مثلا دنبال یک ادیتور برای زبان جاوا هستم و میخوام که با زبان ++C نوشته شده باشه:خط اول رو نگاه کنید، برای اینکه از چند تا تگ در یک جستجو استفاده کنیم، هر بار باید G~ رو اسفاده کنیم.دب تگ ها بسیار زیاد اند و میتونن خیلی به شما موقع جستجو کمک کنن، Facet ها و تگ هارو ببینید و سعی کنید یک تصویری از مهم هاشون ( اون هایی که به کار شما میان ) داشته باشید که موقع جستجو بهتر بتونید فیلتر انجام بدید. و این رو هم بیاد داشته باشید که مثل تمام ساخته های انسان هیچ چیزی کامل نیست و ممکنه بعضی بسته ها تگ های کمی داشته باشن و تگ هاشون اونقدر ها به درد نخورن و برای همین فقط به تگ ها اتکا نکنید و موقع جستجو از آپشن های مختلف حتما استفاده کنید.?upgradable, ~Uاین دستور بسته هایی رو برمیگردونه که میتونن آپگرید بشن.?virtual, ~vاین دستور هم بسته هایی رو برمیگردونه که بسته هایی مجازی اند. برای مثال :virtual?reverse-provides(?installed)?تمام بسته های مجازی ای رو برمیگردونن که توسط بسته های نصب شده ارائه ( provide ) میشن.یقینا نتونستم تمام این عبارات رو توی این مقاله بگذارم، اما نزدیکه به ۸۰٪ اون ها رو که خودم هم ازشون استفاده کرده بودم رو توضیح دادم. امیدوارم از الان به بعد خیلی راحت تر و بهتر به چیزی که نیاز دارید دسترسی پیدا کنید و از توزیع های دبیان بیس و مخازن بزرگ و گران بها شون نهایت استفاده رو ببرید.مهم ترین documentation ی که من ازش استفاده کردم، مستندات خود aptitude هست که از آدرس /usr/share/doc/aptitude/html/قابل دسترسی هست و با دستور $ firefox /usr/share/doc/aptitude/html/en/index.htmlمیشه توی مرورگر اون رو خوند.شاد باشید :)</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Tue, 07 Sep 2021 12:02:09 +0430</pubDate>
            </item>
                    <item>
                <title>چطور یک بسته در دبیان نصب/آپگرید یا حذف می‌شود؟</title>
                <link>https://virgool.io/@liewpl/installupgraderemovedebianpackage-xxduwtl7tco7</link>
                <description>این مقاله در ادامه مقاله اطلاعات همراه با بسته باینری هست، اگه اون رو نخوندید از اینجا میتونید پیداش کنید.در یک سیستم عامل بزرگ و مهمی مانند دبیان گنو/لینوکس، موقع نصب/آپگرید یا حذف بسته ها ممکنه که اتفاقات بسیاری بیوفته و مشکلات عدیده ای بوجود بیاد. الگوریتم های مقابله با این مشکلات در ابزار های مدیریت بسته پیاده‌سازی شدن و قرار نیست همه اون هارو ما بلد باشیم. توی این مقاله میبینیم موقع نصب/آپگرید یا حذف یک بسته چه اتفاقاتی میوفته. چه اسکریپت هایی اجرا میشن و اون اسکریپت ها اصلا از کجا اومدن و ....اسکریپت های پیکربندی Configuration Scripts قبل از اینکه فرایند هایی که گفتم رو ببینیم باید راجع به این اسکریپت ها بدونیم. این اسکریپت ها بخشی از اون meta-information هستن که قبلا توی این مقاله راجع بهشون صحبت کردیم. علاوه بر فایل کنترل ( control.tar.gz ) یک بسته دبیان ممکنه اسکریپت هایی رو هم همراه با خودش داشته باشه که توسط dpkg در زمان های متفاوت پردازش یک بسته صدا زده میشن و وظایف مهمی رو به عهده دارن.دیتابیس دی‌پکیج dpkg databaseتمام اسکریپت های پیکربندی بسته های نصب شده در /var/lib/dpkg/info/ با فرمت زیر دخیره شدنداون فایل های سبز الان مورد بحث ماستهمینطور که توی عکس می‌بینید، این اسکریپت ها با اسم پکیج همراه هستن و اسم اون بسته برای اون اسکریپت ها prefix شده.این پوشه همچنین فایلی رو با پسوند list. برای همه بسته ها داره که لیستی از فایل های متعلق به اون بسته رو نشون میده. به طور کلی preinst script قبل از فرایند نصب و postinst بعد از اون اجرا میشن. و به همین ترتیب prerm قبل از حذف صدا و postrm بعد از اون زده میشن. آپدیت کردن یک بسته به این معنی‌ست که ورژن قبلی حذف و ورژن جدید نصب بشه. این اسکریپت های مخصوص توسط خود توسعه دهنده یا نگه‌دارنده بسته نوشته میشن. چون زیر و بم بسته رو میدونن و میدونن باید چجور با اون رفتار بشه!دنباله های توصیف شده در این بخش اسکریپت های پیکربندی را با نام های خاصی صدا می کند ، مانند old-prerm یا new-postinst. اون ها به ترتیب اسکریپت های موجود در نسخه قدیمی بسته ( *-old ) و اسکریپت های جدید اند ( *-new ) هستند.این دو لینک میتونن یک جلوه تصویری از فرایند های نصب/آپگرید و یا حذف به شما بدن:https://people.debian.org/~srivasta/MaintainerScripts.htmlhttps://www.debian.org/doc/debian-policy/ap-flowcharts.htmlنصب و آپگریداین چیزی هست که در نصب ( یا آپگرید ) بسته اتفاق میوفته: برای بروزرسانی دی‌پکیج old-prerm upgrade new-version رو صدا میزنه.هنوز برای بروزرسانی دی‌پکیج new-preinst upgrade old-version رو اجرا میکنه؛ برای اولین نصب هم new-preinst install رو اجرا میکنه. دی‌پکیج اگه بدونه که این بسته قبلا نصب و حذف شده ( و purge نشده ) ورژن قدیمی رو جلو واژه install میگذاره .الان فایل های بسته جدید استخراج یا باز میشن ( unpack ) اما اگر این فایل ها از قبل وجود داشته باشن، به صورت موقت یک بک آپ ازشون گرفته میشه و بعد با فایل های جدید جایگزین میشن.برای یک بروزرسانی دی‌پکیج old-postrm upgrade new-version رو اجرا میکنه.دی‌پکیج حالا همه فایل های مربوط به اون بسته رو‌ ( file list, configuration scripts, etc. ) بروزرسانی میکنه و اون بک آپ موقت رو حذف میکنهدی‌پکیج حالا فایل های پیکربندی ( configuration files ) رو آپدیت میکنه ، و از یوزر میپرسه که میتونه اتوماتیک این کار رو انجام بده یا نه.و در آخر، دی‌پکیج بسته رو با اجرا new-postinst configure last-version-configured پیکربندی ( configure ) میکنه .حذف بستهاین اتفاقی هست که موقع حذف یک بسته میوفته.دی‌پکیج prerm remove رو صدا میزنهدی‌پکیج همه فایل های مربوط به اون بسته رو به جز‌ فایل های پیکربندی و اسکریپت های پیکربندی ( configuration files and configuration scripts ) رو حذف میکنه.دی‌پکیج حالا postrm remove رو اجرا میکنه. همه اسکریپت های پیکربندی به جز postrm حذف میشوند، اگر یوزر درخواست purge نکرده باشه پروسه همین جا متوقف میشه!برای پرج ( purge ) کامل یک بسته همه فایل های پیکربندی هم همراه با چند کپی ( فایل هایی با پسوند :‌ dpkg-tmp, dpkg-old, dpkg-new ) حذف میشوند، و بعد از آن دی‌پکیج postrm purge رو اجرا میکنه!دیگر پست های من:اسنپ ها در لینوکسچرا باید از اسنپ ها به خوبی استفاده کردسیستم بسته بندی، ابزار ها و اصول اساسی</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Wed, 25 Aug 2021 14:26:25 +0430</pubDate>
            </item>
                    <item>
                <title>چجوری لینوکس من رو عوض کرد؟</title>
                <link>https://virgool.io/@liewpl/howlinuxchangedme-yaq8jizjwuzu</link>
                <description>کوچ از دنیای پنجره های رنگی بسته به آغوش باز گنو و تاکس ( GNU و Tux ) هم میتونه وحشتناک باشه و هم میتونه زندگی آدم رو عوض کنه! سفر کردن به دنیا های متفاوت میتونه هر چیزی به آدم یاد بده. میتونه فرهنگ های نو و زیبا رو به آدم نشون بده و یا دردسر های زیادی رو بهت تحمیل کنه، هر کدوم از اینها میتونن مسیر زندگی و آینده تو رو تغییر بدن. سفر من هم اینجوری شروع شد:مهاجرت به لینوکساواسط تابستان و ماه مرداد بود که ما از شهرکرد آمدیم به کاشان.  بعد از گذشت چندین ماه و آشنا شدن من با زبان پایتون و شروع به یادگیری اون، فهمیدم که گروه های برنامه نویسی زیادی توی تلگرام وجود داره، تا اون موقع استفاده من از تلگرام به صفر میل میکرد. طبق روال گذشته وقتی با کامپیوترم کاری داشتم، باید از روی دیسک کرنل ویندوز توی رم برام لود میشد. D:کیس من هم یه کیس قدیمیه، اون موقع مشخصات سخت افزاریم این ها بود: «یهCPU:‌ Pentium dual core 3.00 GHz  با 2 گیگ رم و یه گرافیک AMD.» دیگه از عوض کردن ویندوز و سنگین بودن و قدیمی بودن ویندوز ۷ خسته شده بودم. تا اون موقع از گنو و لینوکس فقط و فقط اسمشون رو شنیده بودم و هیچ تصوری از خود سیستم عامل و کلا هر چیزی که یه جورای بهش وصل میشه نداشتم. صرفا مکینتاش و ویندوز رو میشناختم. برای کار های مختلف هم مثل عموم مردم از برنامه های کرکی استفاده میکردم. خلاصه بعد از اینکه یه ذره توی تلگرام بودم آروم آروم با یه سیستم عامل جدید آشنا شدم، میدیدم که یک سری ها صحبت از توزیع های لینوکسی ( گنو/لینوکسی ) و نصب و اجرای برنامه ها روی اون ها میکردن و خیلی چیز های دیگه.اینجوری بود که تحقیق شروع شد :) شروع کرده بودم به زیر و رو کردن اینترنت و کسب اطلاعات راجع به این سیستم عامل ( البته میدونم گفتن اینکه لینوکس یه سیستم عامله  غلطه و باید خیلی چیز های دیگه کنارش باشه و اینکه لینوکس صرفا یک کرنل هست. ) گشتیم و گشتیم و گشتیم تا اینکه کلا دیگه تصمیم گرفتم به طور کامل برم روی لینوکس و دیگه هیچ اثری از ویندوز و برنامه هاش روی هارد کامپیوتر و هارد اکسترنالم نباشه!اولین توزیعی که خواستم نصب کنم نسخه Ultimate توزیع Zorin OS بود، چرا؟ چون واقعا از وبسایتش خوشم اومد :) عجیبه اما واقعیه. وقتی داشتم مقاله های مختلفی رو میخوندم و میرفتم راجع به توزیع هایی که اسم برده بودن تحقیق میکردم، وبسایت و اسکرین شات های این توزیع من رو به خودش جذب کرد.محیط زورین اهدایی از mmt  :)واقعا قشنگ بود و آدم رو به خودش جذب میکرد. این نسخه یک نسخه پولی هست اما میتونید از سایت Downloadly.ir اون رو به صورت رایگان دانلود کنید. قبل از اینکه دانلود اش کنم طریقه نصب اش رو از توی سایت خودش خوندم. تازه با مفهوم جذابی به اسم بوتیبل کردن آشنا شده بودم. یادم نیست که سایت خودش نرم افزار balena etcher رو معرفی کرده بود یا اینکه جای دیگه ای دیدم اما balena etcher رو دانلود و فایل iso اش رو روی فلشم بوتیبل کردم. DE این توزیع GNOME هست که برای رم ۲ واقعا کم و اذیت کننده اما اون موقع اصلا هیچ تصوری از این چیزا نداشتم.نرم افزار عالی برای بوتیبل کردن iso های لینوکسیچه لحظه خوبی بود ، خداحافظی با ویندوز !! ( البته خداحافظی نه، فورمت ( format ) بی برگشت تمامی باینری های ویندوز ۷ از روی هارد کامپیوترم :) )وقتی نصب شد. خیلی خوشحال بودم! قبلش یه دوره کوتاه و خوب از دانلودلی پیدا کرده بودم و شروع کردم به نگاه کردن و جزوه نوشتن و ذوق کردن با لینوکس! تجربه اینکه ۹۰ درصد چیزی که احتیاج داری از قبل روی سیستم نصب شده، دیگه لازم نیست به دنبال کرک نرم افزار باشی و با نرم افزار های جدیدی آشنا میشی، با ترمینال کار میکنی و خیلی چیز های دیگه من رو بیشتر رو به جلو هل میداد تا بیشتر با لینوکس آشنا بشم. اما گنوم برای من سنگین بود و گاه و بیگاه ( مثلا موقع استفاده از مرورگر ها و پایچارم ) سیستم فریز میشد و اعصاب من هم خورد....! بعد از این قضایا رفتم به وبسایت زورین و دیدم یک نسخه Lite داره که به گفته خودش واسه سیستم هایی با قدمت ۱۵ سال به بالاست ( اگه اشتباه نکنم DE اش XFCE باشه. ) اون رو نصب کردم و دیدم بله چقدر سبکه و راضی شدم. اما بعد از مدتی اون شور و اشتیاق فروکش کرد و دیگه یه کاربر تازه‌کار عادی لینوکس شده بودم. درگیر درس و مشق شدم و بعد از تموم شدن دیدن اون دوره دیگه چیز جدیدی یاد نگرفتم.توی تلگرام هم دو سه تا گروه پایتون داشتم و دیگر هیچ. هنوز با گروه های لینوکسی آشنا نشده بودم. یه فاصله ای افتاد و تصمیم گرفتم که برم اوبونتو نصب کنم.دلیل اش هم این بود که این اسم نقل هر مقاله و وبسایتی بود :) اون جا بود که کم کم متوجه شدم که چیزی به اسم DE وجود داره و در این اقیانوس نرم افزار متن باز و آزاد DE های مختلفی هست که:  &quot;بسیار خفن می نمود در نظرم.&quot;فهمیدم که اوبونتو از DE گنوم استفاده میکنه. یه روز آخر هفته دانلود و نصبش کردم امااااا باز هم مشکل کمبود فضای رم و فریز شدن سیستم روی سیستم سبز شد. فهمیدم که یکی از علل وجود DE های مختلف همین مصرف رم اون هاست که اون ها رو از هم متمایز میکنه ( البته دلایل خیییلی بیشتر هم داره که اون موقع فقط این رو میدونستم )خیلی با احتیاط برنامه باز میکردم و هیچ وقت دو تا چیز رو باهم باز نمیکردم. هر وقت که بیکار بودم اون برنامه ای که طرز استفاده و کار با گنوم رو آموزش میداد رو میخوندم و تمرین میکردم ( اسمش یادم نیست روی خود اوبونتو پیش‌فرض نصب بود. ) خیلی داشت خوش میگذشت، کلی شورت کار باحال و جذاب که واقعا کار آدم رو سریع میکرد. خدایی‌اش DE باحال و قشنگیه! بعد از اینکه دیگه کفرم بالا اومده بود و دیگه میخواستم روون با کامپیوترم کار کنم رفتم دنبال توزیعی بگردم که سبک باشه و دیگه اینجوری اذیت نشم و این شد که با Ubuntu Flavours اشنا شدم. واقعا یکی از شاهکار هان، تیم های جدایی که بیس رو اوبونتو برداشتن و تمرکزشون رو روی DE گذاشتن!!!این شد که با DE های سبک تر مثل LXDE ( اون زمان هنوز LXQT متولد نشده بود یا اگر هم شده بود معرفی نشده بود ) و XFCE آشنا شدم. اولین بار Lubuntu نصب کردم و کلی حالم گرفته شد .زشت بود و میزد توی ذوق آدم واقعا فکر میکردم آخه چرا روی این دارن وقت و زندگی شون رو تلف میکنن!!!  این شد که یکی از long lasting توزیع هایی که نصب و استفاده کردم شد Xubuntu. واقعا XFCE برای ۲ گیگ رم خوب بود. مرورگر رو با پایچارم باز میکردم و مشکلی نبود. هیچی دیگه زندگی برگشته بود به روال عادی. گذشت و گذشت تا اینکه گفتم &quot;خوب برو یه رم دیگه بگیر خودت رو راحت کن، مجبوری !!!! &quot; بله با این جمله تاریخی یک تحول بزرگ، هم درون کیس من و هم درون سخت افزار های کیس من در شرف وقوع بود.زنگ زدم به یکی از دوستام. چون قبلا از ارتقا و خرید سخت افزار کامیپوتر صحبت کرده بودیم، گفتم زنگ بزنم ببینم باید چه کار کنم. بعد از اینکه راجع به خود رم ها ( ddr3, ddr4 ) و ظرفیت مادربرد و این چیزا یه چیز هایی داشت دستگیرم میشد ، رفیقم گفت برو کیس ات رو باز بکن، مدل دقیق مادربردت رو گوگل کن برو وبسایت تولید کننده مادربردت ( GYGABِYTE ) و راجع بهش مطالعه کن. مادربرد من تا هشت گیگ رم ddr3 رو پشتیبانی میکنه. رمی که روی یکی از اسلات هاش بود رو ( دو تا اسلات رم داره ) در آوردم و فهمیدم فرکانسش ۱۳۳۳ مگاهرتزه و باید یه رم ddr3 با همین فرکانس پیدا کنم. اول داشتم دنبال یه رم ۴ گیگ هم مارک خودش میگشتم که نتایج خیلی جالبی نداشت. این شد که رفتم خیابان بانک ها ( جایی است در کاشان که بانک ها در آن تجمع دارند :) ) اونجا شبیه به سه راه سینما توی شهرکرده ( این مکان در واقع چهار راهی است که در یکی از خیابان هایش سینما بهمن قرار دارد و بازار کامپیوتر شهرکرد به حساب می‌آید. ) البته کوچک تر. چند تا مغازه کامپیوتری اونجا سراغ داشتم و رفتم دنبال رم! بعد از زنگ های دوباره و مشورت و اینا یه رم ۴ گیگ کینگستون خریدم و خوشحال و شادان و آماده برای اون تحول بزرگ به سمت خونه رکاب میزدم.وقتی رسیدم خونه رم رو از توی جعبه یا کاور پلاستیکی اش در آوردم و کیس رو باز کردم و جا زدم. لحظه، لحظه خیلی حساسی بود. روی زوبونتو از داک پلنک ( plank ) استفاده میکردم. خود این داک یه ویجت داشت که میزان رم اشغال شده رو با یه نمودار دایره ای و میزان کارکرد سی پی یو رو با رنگ نشون میداد. تا قبل از اینکه مجموع رم ام ۶ گیگ بشه همیشه یک پنجم تا یک چهارمش اشغال بود. وقتی که صفحه لاگین اومد رمز رو زدم و وقتی که داک باز شد دیدم که عهههه هنوز که ۲ گیگ رم دارم :( هیچی دیگه کامپیوتر رو خاموش کردم و زنگ زدم به رفیقم، بهم گفت که ۱۰۰ درصد درست جا نرفته و جا زدنش یه قلق خاصی داره. دوباره کیس رو باز کردم و با اون رم دو گیگ مقایسه کردم، حرف رفیقم درست بود. باید موقع جا زدن رم کناره هاش رو همزمان با بستن اون دوتا خاری که نگهش میدارن فشار داد تا کامل بره جا. دوباره کیس رو روشن کردم و دیدم بــــــــــــــــــله ۵.۹ گیگ رم الان در دسترس هست :)  سر از پا نمیشناختم . ۲ تا پنجره پایچارم و دو تا مرورگر با ۵ تا تب باز میکردم آخ نمیگفت و خیلی که میشد تا ۵ گیگ پر میشد.اینجا بود که گفتم دیگه میرم که توزیع سنگین نصب میکنم. تعریف KDE رو شنیده بودم . و باز هم به مزه های اوبونتو مراجعه و بدون هیچ معطلی Kubuntu رو نصب کردم. این دومین long lasting توزیع من بود. از کانال linuxscoop یکی از شخصی سازی هاش رو انتخاب و اعمال کردم. اولش Big sur رو خیلی دوست داشتم و چند ماهی با اون کیف میکردم. بعدش دوباره عوضش کردم و تا یه مدت مدید با اون زندگی میکردم. در همین حین دیگه تلگرامم مثل سابق نبود.پر شده از گروه های برنامه نویسی و لینوکس شده بود  و داشت به اطلاعات لینوکسی ام اضافه میشد.این کوبونتوی من بود.دانشی که نسبت به فلان بیس ها داشتم صرفا در حد مزه های اوبونتو بود و راجع به دبیان و آرچ و سوزا RHEL چیزی صرفا یه چیزهای شنیده بودم. راجع به توزیع های غلتان و پایدار ( Rolling and Stable ) هم اطلاعات کمی داشتم. بعد از تحقیق راجع به این ها نتیجه های بسیـــــــــــــــــاری گرفتم و کلا سراغ غلطان ها نرفتم ( که دلایل زیادی داشت، یکی‌شون برخورد با چند تا بچه متعصب متنفر از دبیان و اوبونتو بود. کار رو چند تا گروه به جایی برام رسونده بودن که دیگه میخواستم با اوبونتو خداحافظی کنم. یه جور جنگ رسانه ای و دروغ پراکنی و بزرگ نمایی بیخودی بود. ای خدا چقدر وضعیت بدی داشتم !!‌ البته صرفا بخاطر این نبود، اصلا اینطور نیست ) همین جور که داشتم دروغ های اونها رو پیش خودم با سرچ و جستجو پاک میکردم، یه اتفاق خیییلی بزرگ افتاد که الان هم هنوز درگیرش ام و این اتفاق بسیااااار بر من تاثیر مثبت گذاشت: &quot; آشنا شدن با واژه SysAdmin &quot;. توی چند سال اخیر دو سه تا اتفاق خیلی مهم برای من افتاده بود که آخریش همین واژه بود. این کلمه من و تمرکز من رو به شدت تحت تاثیر قرار داد. آروم آروم داشتم راجع بهش تحقیق میکردم و از این وبسایت به اون مقاله و از این گروه به اون گروه میرفتم.توی یه گروه دواپس از یکی از ادمین هاش که آدم بسیار دانایی بود و توی حوزه تخصصی اش تبحر زیادی داشت، یه سوال در مورد اینکه چجور میشه یه سیستم ادمین شد پرسیدم و از ایشون مشورت و منبعی برای شروع خواستم. ایشون همیشه موقع جواب دادن اصولا چیزی رو از قلم نمیدازن و با حوصله زیادی که دارن تقریبا به  جای یک پاسخ به شما مقاله ای جامع تحویل میدن! برای من هم همینطور شد. وقتی داشتم جوابشون رو میخوندم، به قسمتی رسیدم که یک کتاب رو معرفی کرده بودن برای شروع. &quot;The Debian Administrator&#x27;s Handbook&quot; بسیار از این کتاب تعریف کرد و بهم گفت میتونی از فلان و بهمان و بیسار هم شروع کنی اما اگه من جای تو بودم همین کتاب رو میخوندم. بعد از تشکر  بسیار، رفتم سراغ کتاب. وقتی اسمش رو گوگل کردم اولین نتیجه وبسایت کتاب بود.این کتاب رو دو تا از توسعه دهنده های هسته دبیان نوشته اند ( تا این موقع اکثر توزیع هارو میشناختم و شناخت خیلی بهتری نسبت به قبل داشتم. ) و این کتاب رو با لایسنس GPL منتشر کرده بودن. واقعا چه حرکت بزرگی، چه فرهنگ زیبایی که دکتر استالمن شروع کرده و پرورش داده اند. میشه گفت این فرهنگ داره به خوبی رشد میکنه و به بلوغ میرسه ( شایدم بشه گفت رسیده :) ) نسخه بروز کتاب رو از وبسایتش دانلود کردم و توی خبرنامه اش ثبت نام کردم. از فرداش شروع کردم به خوندن کتاب توی کامپیوتر امااا بعد از دو سه روز، هم چشمام اذیت شد و هم مادرم بهم هشدار داد که اگر نسخه فیزکی نداشته باشی تحریم خواهی شد. :))هیچی دیگه دنبال جایی بودم که کتاب رو چاپش کنم. یکی از دوستام قبلا بهم گفته بود فلان کتاب رو از فلان جا سفارش دادم و گفته بود که سفارش چاپ هم میگیرن. رفتم اینستا و پیجشون رو دیدم ( Instagram ID: Skybooks.ir ). وااااقعا کارشون بیسته. کیفیت عالی و قیمت ارزان باورنکردنی. این کتاب ۵۱۴ صفحه‌ست. برای ادمین کتاب رو فرستادم و قیمت خواستم. گفت با جلد سخت و چاپ سیاه و سفید میشه ۱۲۲ هزار تومن. هیچی دیگه من هم از خدا خواسته سفارش دادم. از وقتی که کتاب رسیده دارم میخونمش، نوت برمیدارم و تمرین میکنم. در یک کلمه وااااقعا عالی نوشته شده و به همه پیشنهادش میکنم.حالا چرا این ها رو گفتم، همه این ها مقدمه هایی بودن برای آخرین مهاجرت توزیعی من. بله همینطور که حدس زدید نصب دبیان !!!!وقتی که تصمیم گرفتم دبیان رو نصب کنم آخرین نسخه استیبل اش Debian 10 Buster بود. اما از شانس بسیار خوب من فرداش این مقاله رو خوندم :‌ &quot;دبیان ۱۱ با اسم بولز آی ( Debian 11 Bullseye ) قراره که منتشر بشه&quot; خب شما بگید چی بهتر از این :) بعد از چند روزی فهمیدم که قراره ۱۴ آگوست یا ۲۳ مرداد release بشه. صبر و صبر و صبر تا اینکه روز ۲۴ مرداد توزیع نصب شد .بولزآی مانند پیامبری برمریدان او نازل شد و بسته های تازه برایشان آورد :)الان هم که دارم این داستان رو مینویسم دبیان به خوبی داره روی سیستم کار میکنه و فکر میکنم آخرین توزیعی باشه که روی سیستم ام نصبه و دیگر تعویض نخواهد شد :))دبیان زیبای من :)امیدوارم افراد بیشتری با گنو/لینوکس آشنا بشن و فرهنگی که دکتر استالمن شروع کردن رو درک کنن.باقی پست های من رو هم از این زیر میتونید بخونید:اسنپ ها در لینوکسچرا باید از اسنپ ها به خوبی استفاده کرد؟و یک رشته مقاله که در مورد سیستم بسته بندی در دبیان اند:سیستم بسته‌بندی، ابزار ها و اصول اساسی</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Sun, 22 Aug 2021 17:29:51 +0430</pubDate>
            </item>
                    <item>
                <title>اطلاعات همراه با بسته های باینری ( Package meta-info )</title>
                <link>https://virgool.io/@liewpl/%D8%A7%D8%B7%D9%84%D8%A7%D8%B9%D8%A7%D8%AA-%D9%87%D9%85%D8%B1%D8%A7%D9%87-%D8%A8%D8%A7-%D8%A8%D8%B3%D8%AA%D9%87-%D9%87%D8%A7%DB%8C-%D8%A8%D8%A7%DB%8C%D9%86%D8%B1%DB%8C-package-meta-info-uq6phe2dicwz</link>
                <description>توی مقاله قبلی راجع به خود بسته های باینری صحبت کردم اگه نخوندید از اینجا اون رو بخونید بعد بیاید اینجا تا ادامه بدیم.سلام.الان یک شناخت مختصر از بسته های باینری و محتویات اون ها داریم. توی قدم اول ببینیم اون فایل control.tar.gz چی هست و چی داره و به چه کاری میاد :)یک بسته دبیان نه تنها فایل های اجرایی و اجزای مهم دیگه رو داره، بلکه یک قسمت از دنیای بزرگ تری هست که رابطه اش با بقیه بسته ها رو شرح میده ( ملزومات، پیش‌نیاز ها، تعارضات ( conflicts )، پیشنهاد ها ). همچنین اسکریپت های مورد نیازی که نگهدارنده و یا maintainer بسته برای اون بسته در زمان حیاتش نوشته را ( نصب ، حذف و آپدیت ) داراست. این اطلاعات توسط ابزار های مدیریت بسته استفاده میشن و قسمتی از خود اون نرم افزار نیستن و چیز هایی فرا بسته‌ای نام میگیرن ( یعنی اطلاعاتی راجع به اطلاعات دیگه به ما میدن :| )فایل کنترل: the control fileاین فایل از ساختاری شبیه به سرصفحه های ایمیل ( email headers ) داره که توسط استاندارد ( RFC 2822 ) تعریف میشن و توسط Debian Policy و manual page هاش خیلی خوب شرح داده شدن. برای Debian Policy به اینجا و اگه میخواهید من پیج هاش رو بخونید به deb-control(5) و deb822(5) مراجعه کنید.برای مثال کنترل فایل بسته apt اینگونه هست:حالا بیاید فیلد های این فایل رو جدا جدا با هم بررسی کنیم ( اینجا چند تا از مهم هاش رو میگم )پیش‌نیاز ها : فیلد Dependsپیش‌نیاز های مورد نیاز بسته برای اینکه درست کار کنه توی این فیلد نوشته شدن. این فیلد یک لیستی از شرط هاست که باید همه تایید بشن یعنی این لیست یه لیست اجباریه، اگر برای مثال بخواید بسته ای رو با دی‌پکیج نصب کنید، دی‌پکیج میاد این فیلد رو نگاه میکنه و اگر حتی یکی از شرط ها تحقق نیافت فرایند رو متوقف میکنه. این اطلاعات توسط ابزارهایی مثل apt استفاده میشن تا کتابخانه ها، درایور‌ها، ابزار ها و خلاصه همه‌ی چیزی که اون بسته بهشون نیاز داره رو با ورژنی خاصی که براش توی این فیلد مشخص شده فراهم کنن. برای هر پیش‌نیاز میشه یک دامنه ای از ورژن ها رو تعریف کرد. مثلا عکس بالا رو نگاه کنید بسته libc6 جلو اش نوشته ( &gt;= 2.3.4 ) این یعنی برای اینکه apt درست کار کنه به این بسته و با ورژن مساوی یا بالاتر از 2.3.4 نیاز داره!توصیه شده ها، پیشنهاد ها  Recommends, Suggestsاین دوتا فیلد پیش‌نیاز هایی رو معرفی میکنن که اجباری برای نصبشون نیست. بسته های فیلد توصیه شده ها ( Recommends ) که بسیار مهم تر از بسته های فیلد پیشنهاد ها هستن، قابلیت ها و توان‌مندی های بسته نصبی رو به میزان قابل توجهی بهتر میکنن ولی عملکرد پایه ای بسته نصبی بهشون وابسته نیست و اگر هم نباشن مشکلی نیست.بسته های فیلد پیشنهاد ها از توصیه شده ها اهمیت کمتری دارن و نشان می دهد که بسته های خاصی ممکنه ابزار مربوطه را تکمیل و عملکرد اون را افزایش دهند.شما بهتره که همیشه بسته های فیلد توصیه شده ها رو نصب کنید، مگر اینکه دقیقا بدونید چرا به اون ها یا چند تا از اون ها نیازی ندارید. این رفتار برای APT هم صدق میکنه تا وقتیه که خودتون تغییرش نداده باشیدو از اون لازم نیست که بسته های فیلد پیشنهاد ها رو نصب کنید مگر اینکه بدونید برای چی بهشون نیاز دارید,رفتار APT رو میشه با کانفیگ کردن اون با :
 APT::Install-Recommends و APT::Install-Suggests 
و یا موقع نصب با آپشن های
apt --[no-]install-recommends --[no-]install-suggests install package
کنترل کردفیلد Pre-Depends یک Depends سخت گیرانه ترهمین‌طور که از اسمش پیداست این فیلد حتی مهم تر از فیلد پیش‌نیاز هاست.بسته هایی که توی فیلد پیش‌نیاز ها هستن باید قبل از استخراج و کانفیگ شدن بسته ای که اون ها رو به عنوان پیش‌نیاز قید کرده نصب و کانفیگ بشن که یه چیز عادی و معمولی ای هست. اما بسته یا بسته هایی که در فیلد Pre-Depends هستن باید حتی قبل از اینکه اسکریپت پیش از نصب ( pre-installation script ) بسته اجرا بشه، نصب و کانفیگ بشن. یعنی قبل از اینکه اراده کنیم بسته ای رو نصب کنیم باید اول Pre-Depends هارو نصب و کانفیگ کنیم و بعدش قصد نصب کنیم :))این فیلد برای APT بسیار مهم هست و خودش همه اقدامات لازم رو برامون انجام میده.جالبه بدونید که Pre-Depends ها خیلی کم پیشنهاد میشه که استفاده بشن ( یعنی دولوپر ها خیلی کم باید از اون ها استفاده کنن منظورم کسایی هست که میخوان بسته های رو ارائه بدن یا نگهداری کنن ) حتی به توسعه دهنده پیشنهاد میشه قبل از اینکه میخوان بسته ای رو توی این فیلد بگذارن، بیان و توی debian-devel@lists.debian.org راجع بهش سوال بپرسن، بحث کنن و مشورت بگیرن.تعارضات : فیلد Conflictsاین فیلد مشخص میکنه که چه بسته هایی نمیتونن همزمان با هم نصب بشن. معمول ترین اتفاقی که ممکنه رخ بده اینکه دو تا بسته فایلی دارن که توی هر دو اون ها اسم و مسیرش یکی باشه، یا سرویسی رو روی یک پورت TCP ارائه میدن.دی‌پکیچ اگر بسته ای رو روی سیستم دید که با بسته ای که داره نصب میکنه تعارض داره، عملیات رو متوقف میکنه، مگر اینکه بسته جدید بگه من اون فایل رو جایگزین خواهم کرد، و در این صورت دی‌پکیج بسته جدید رو با بسته قدیمی جایگزین میکنه. APT هم همیشه به حرف شما گوش میده و اگر چنین موقعیتی براش پیش بیاد  میپرسه که آیا اون بسته ای رو که مشکل ایجاد میکنه، حذف کنم؟ناسازگاری ها : فیلد Breaksاین فیلد هم تأثیری شبیه به فیلد Conflicts داره ، اما دارای معنی خاصیه. این فیلد نشون میده که نصب یک بسته ، بسته دیگری (یا نسخه های خاصی از اون ) را &quot;خراب&quot; می کنه. به طور کلی ، این ناسازگاری بین دو بسته گذرا است و رابطه Breaks به طور خاص به نسخه های ناسازگار اشاره می کنه.دی‌پکیج از نصب بسته ای که عملکرد بسته دیگه ای رو که روی سیستم هست خراب کنه ، امتناع می کنه و apt-get با به روز کردن بسته ای که مشکل ایجاد میکند، مشکل رو حل می کنه.این وضعیت ممکنه در مورد به روزرسانی های که سازگاری با گذشته ندارن ( They are not backward compatible ) رخ بده : این مورد در صورتی اتفاق می افتi که نسخه جدید دیگر با نسخه قدیمی کار نکنه و بدون ایجاد شرایط خاصی باعث خرابی برنامه دیگری بشه. فیلد ناسازگاری ها  مانع از مواجه شدن کاربر با این مشکلات می شه.مواردی که ارائه میشوند :‌ فیلد Providedاین فیلد یکی از جذاب ترین مبحث هارو معرفی میکنه به اسم بسته های مجازی ( virtual packages ) این بسته های قوانین مهمی دارن و میشه براشون یک مقاله جدا نوشت اما یه اشاره کوچک میتونه فضا رو برامون روشن تر کنه.ارائه یک سرویسهمه سرور های پیام ( mail servers ) مثل postfix یا sendmail سرویسی رو به عنوان mail-trasport-agent ارائه میدن، با توجه به این، هر بسته ای که به این سرویس احتیاج داشته باشه تا بتونه فعالیت کنه، مثل بسته های مدیریت کننده mailing list ها ( برای مثال smartlist یا sympa ) خیلی ساده توی فیلد پیش نیاز ها قید میکنن که من به این سرویس احتیاج دارم نه اینکه بیان کلللی بسته دیگه رو تک تک نام ببرن، و بعد هم APT میاد بسته ای که این سرویس رو ارائه میده نصب میکنه و همه چیز میشه Up and running :)فایل هایی که جایگزین میشوند: فیلد Replacesاین فیلد به ما میگه که این بسته فایل هایی داره که در بسته دیگه ای هم حضور دارن و این اجازه رو به مدیر بسته میده که اون ها رو موقع نصب بدون هیچ اشکالی جایگزین کنه.فایل های مهم دیگه‌ای همراه با کنترل فایل در بسته باینری وجود داره که زندگی بسته به اون ها وابسته‌ست، اینجا هم یه نگاهی به اونها میندازیم و هم می‌بینیم موقع نصب بروزرسانی و یا حذف بسته چه اتفاقاتی میوفته.</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Wed, 18 Aug 2021 22:10:59 +0430</pubDate>
            </item>
                    <item>
                <title>ساختار بسته های باینری ( ‌binary package )</title>
                <link>https://virgool.io/@liewpl/%D8%B3%D8%A7%D8%AE%D8%AA%D8%A7%D8%B1-%D8%A8%D8%B3%D8%AA%D9%87-%D9%87%D8%A7%DB%8C-%D8%A8%D8%A7%DB%8C%D9%86%D8%B1%DB%8C-binary-package-xykcmtuh2ydu</link>
                <description>اگه مقاله قبلی رو نخوندید از اینجا اون رو یه نگاهی بندازید. مقاله قبلی یه مقدمه راجع به این سری مقاله هاست.سلامقراره که باهم یه سفر داشته باشیم به دنیای بسته بندی توی دبیان. قراره راجع به بسته های باینری ( binary package ) و بسته های منبع ( source package ) صحبت کنیم. اولی فایل هایی هستن که به طور مستقیم توسط دی‌پکیج ( dpkg ) مدیریت میشن و دومی حاوی کد منبع ( source code ) و همچنین دستوراتی برای ساخت بسته های باینری از اون کد منبع است.deb packageساختار بسته های باینریبسته های دبیان طوری طراحی شدن که بشه روی هر سیستم یونیکسی که دستور های ar, tar, xz یا بعضی وقت ها gzip یا bzip2 رو داشته باشه استخراج کرد. این ویژگی به ظاهر بی اهمیت برای portability و disaster recovery یا به فارسی قابلیت حمل و بازیابی در هنگام یک فاجعه خیلی مهم هست.( می‌دونم معادل ها اون چنان با مسما نیستن. همون انگلیسی‌شون بهتره این برای اینکه تقریبا کلماتی تخصصی اند و ترجمه یا معادلشون جالب در نمیاد. )بیاید فرض کنیم شما اشتباهی برنامه dpkg رو حذف کردید !!! خب حالا که این اتفاق افتاده شما دیگه نمیتونید بسته های دیگه رو نصب، حذف یا آپدیت کنید و این یعنی فاجعه !! اما خود دی‌پکیج هم یک بسته دبیانی هست و میشه بسته باینری اش رو دانلود کرد و استخراج کرد و دستی نصب کرد :)بیاید حالا یه نگاهی به یک بسته باینری بندازیممحتویات یک بسته باینریفایل debian-binary : این فایل، یک فایل متنی خیلی ساده‌ست که فقط ورژن دب فایل رو نشون میده. که توی دبیان باستر ( Debian 10 Buster ) ورژن ۲.۰ هست.فایل control.tar.gz : این فایل همه اطلاعات مربوط به بسته رو داخل خودش داره ( meta-information که معادلش میشه فرا اطلاعات :|‌‌  ) مثل اسم و ورژن بسته، و همچنین اسکریپت هایی که قبل، حین و بعد از نصب ( یا حذف ) این بسته باید اجرا بشن. بعضی از این اطلاعات به ابزار های مدیریت بسته این امکان رو میدن که بررسی کنن آیا این بسته قابل نصب روی سیستم ( یا حذف از سیستم ) هست یا نه.فایل data.tar.xz, data.tar.gz, data.tar.bz2 : این فایل همه چیز هایی باید از بسته استخراج بشن رو داره، در این فایل فایل های اجرایی ( executable files ) کتابخانه ها مستندات و ... قرار دارن.سعی میکنم که مقالات کوتاه کوتاه باشن که هم بشه اونها رو راحت خوند و هم اینکه اطلاعات زیادی نباشه که یک باره آدم بخواد به حافظه بسپره. هم اینکه طبقه بندی شده باشن.ممنون که این مقاله رو مطالعه کردید. توی مقاله بعدی میریم داخل فایل control.tar.gz و میبینیم این فایل باارزش چه چیز هایی داخل خودش نگه میداره و چرا این قدر مهمه .موفق باشید!</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Wed, 18 Aug 2021 22:07:28 +0430</pubDate>
            </item>
                    <item>
                <title>سیستم بسته بندی: ابزار ها و اصول اساسی</title>
                <link>https://virgool.io/@liewpl/%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D8%A8%D8%B3%D8%AA%D9%87-%D8%A8%D9%86%D8%AF%DB%8C-%D8%A7%D8%A8%D8%B2%D8%A7%D8%B1-%D9%87%D8%A7-%D9%88-%D8%A7%D8%B5%D9%88%D9%84-%D8%A7%D8%B3%D8%A7%D8%B3%DB%8C-yflfjahgglci</link>
                <description>به عنوان یک مدیر سیستم دبیان، شما به طور معمول بسته های deb را مدیریت میکنید، زیرا اون ها شامل واحد های عملکردی یکسانی هستن، که نصب و نگهداری اون ها رو تسهیل میکنن. بنابراین ایده خوبیه که بدونیم اونها چی هستن و چطور از اونها استفاده کنیم.سلام.من قراره یک رشته مقالاتی راجع به سیستم بسته بندی توی دبیان بنویسم. این سری مقالات با این ترتیب قراره منتشر بشن.ساختار بسته های باینریاطلاعاتی که همراه با بسته ها هستن ( Package meta-information ) در دبیان چطور یک بسته نصب/آپگرید یا حذف میشه؟ساختار بسته های منبع ( Source package )سیستم بسته بندی دبیان، یه سیستم جذاب و آسان برای یادگیری هست. امیدوارم که این سری مقاله اطلاعات خوبی رو با شما به اشتراک بگذارن.</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Wed, 18 Aug 2021 22:04:37 +0430</pubDate>
            </item>
                    <item>
                <title>استفاده از یه فیلترشکن رایگان و بدون محدودیت حجم!</title>
                <link>https://virgool.io/@liewpl/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%DB%8C%D9%87-%D9%81%DB%8C%D9%84%D8%AA%D8%B1%D8%B4%DA%A9%D9%86-%D8%B1%D8%A7%DB%8C%DA%AF%D8%A7%D9%86-%D9%88-%D8%A8%D8%AF%D9%88%D9%86-%D9%85%D8%AD%D8%AF%D9%88%D8%AF%DB%8C%D8%AA-%D8%AD%D8%AC%D9%85-od1pswjqzl7m</link>
                <description>سلام.من تقریبا یه سال و خورده ای شده که سیستم عامل اصلی‌ام یه توزیع گنو/لینوکس هست.اون اولا دنبال یه فیلترشکن میگشتم و یکی دوتا پیدا کردم اما نه خیلی با لینوکس راحت بودم (‌یعنی کمتر با دستور ها و کار کردن باهاش آشنا بودم) و نه اینکه آموزش خوبی واسشون پیدا کردم (‌چهار تا ویدیو توی یوتوب اون هم به زبان هندی :) بود که کلا نتونستم.) لینوکس هم مثل ویندوز نیست که خیلی راحت بتونید یه فایل نصبی از یه فیلترشکن ( مثلا مثلا سایفون )‌ پیدا کنید و نصبش کنید!تاااااا اینکه ( این صحبت به زمانی بر میگرده که از کروم استفاده شدید میکردم )‌ توی یکی از مقاله های پیشنهادی گوگل کروم روی گوشیم یه مقاله از یه سایت اومد که طریقه نصب ProtonVPN روی لینوکس رو آموزش میداد. هیچی رفتم راجع بهش تحقیق کنم که دیدم عه!! سایت خودش فیلتر هست و برای نصب فیلترشکن احتیاج به فیلترشکن دارم :) با فیلترشکن متن بسته (‌که معلوم نبود چی ازم جمع میکنه )‌ و پر از تبلیغ گوشیم رفتم سایتش و دیدم که این VPN رو میشه یه سرویس سوپر پلتفرم دونست.( Linux, Mac, Windows, Android, iOS, Android TV, ChromeBook رو پشتیبانی میکنه !! ) یکی دیگه از خوبی های این سرویس متن باز بودن کلاینت هاش بود و اینکه نه تبلیغی داره و نه محدودیت حجمی ! تازه یک پلن ( plan ) رایگان هم داره که خیلی راحت با یه ثبت نام ساده میشه ازش استفاده کرد!حالا بیاید بریم این VPN خوب رو، روی سیستم‌مون نصب کنیم!پروتون وی پی ان یه وی پی ان پر سرعت و سوییسی هست که با استفاده از یک تونل ( tunnel ) رمزنگاری شده از دیتا های مهم شما مثل رمزعبور هاتون محافظت میکنه. این سرویس ویژگی های مهمی رو برای شما داره:رمزنگاری کامل دیسک ها روی سرور های پروتون  که در برابر حمله ها از اطلاعات شما محافظت میکنهاستفاده از پروتوکل های قوی مثل KEv2/IPSec و OpenVPNسیاست بدون لاگ ( no log policy ) که فعالیت شما توی اینترنت رو ذخیره نمیکنه.و ...برای استفاده از پروتون وی پی ان باید یه حساب کاربری داشته باشیماگر دارید با تلفن این مقاله رو میخونید فیلترشکنی که دارید رو برای آخرین بار :) روشن کنید تا بریم سایت خود پروتون و ثبت نام کنیم و بعدش دیگه فیلترشکن هاتون رو میتونید دیگه روشن نکنید یا اصلا حذفشون کنید.اگر هم روی کامپیوتر هستید روی مرورگری که دارید افزونه hoxx vpn رو نصب کنید. مراحل نصب و راه اندازی خیلی ساده ای هم داره و وقتی که پروتون اوکی شد حذفش کنید.ثبت نامبریم به پروتونقسمت Pricing و پلن رایگاناین پلن ۲۳ تا سرور توی سه تا کشور ژاپن، هلند و آمریکا در اختیار شما میگذاره.روی پلنی رایگانی که توی تصویر با حاشیه قرمز مشخص شده کلیک کنید.این شما رو به صفحه ثبت نام میبره. برای ثبت نام اطلاعاتی که خواسته رو پر کنید.ثبت نام پروتون وی پی انوقتی که کار ثبت نام تموم شد و به حساب‌تون ورود کردید ( login ) طبق تصویر روی حساب ( Account ) و روی OpenVPN / IKEv2 username کلیک کنید. اینجا اطلاعات مربوط به نام کاربری و رمز عبور شما رو بهتون نشون میده.نام کاربری و رمز عبور OpenVPNما برای ثبت حساب‌ روی کامپیوترمون به این دو تا احتیاج داریم، پس صفحه مرورگر رو همینطور بگذارید و ترمینال‌تون رو باز کنید.نصب OpenVPN برای سیستم های Debian/Ubuntu پایه$ sudo apt update
$ sudo apt install openvpn dialog python3-pip python3-setuptoolsنصب ProtonVPN CLI$ sudo pip3 install protonvpn-cliنصب OpenVPN  و ProtonVPN CLI برای سیستم های RHEL/CentOS 8 پایه و Rocky Linux$ sudo dnf install -y openvpn dialog python3-pip python3-setuptools
$ sudo pip3 install protonvpn-cliنصب OpenVPN  و ProtonVPN CLI برای سیستم های ArchLinux/Manjaro پایه$ sudo pacman -S openvpn dialog python-pip python-setuptools
$ sudo pip3 install protonvpn-cliفعال سازی و راه‌اندازیوقتی که OpenVPN روی سیستم نصب شد، وقت این میرسه که ProtonVPN رو برای سیستم کانفیگ کنیم. برای این کار:$ sudo protonvpn initاون زبانه مرورگری که گفتم باز بگذارید برای اینجا بود.یوزرنیم‌تون و پسوردی که توی اون زبانه هست رو کپی کنید و اینجا وارد کنید.سپس با زدن عدد یک پلن رایگان رو انتخاب کنید.حالا اینجا باید بین TCP و UDP انتخاب کنیم . هردوشون خوبن اما UDP سرعت بهتری داره!با زدن عدد ۱ این گزینه رو هم تایید کنید و بعدش با زدن حرف y اطلاعات رو تایید کنید.آخر سر هم پیام موفقیت آمیز بودن رو دریافت میکنیم :)غیرفعال سازی IPv6 روی لینوکساز اونجایی که کلاینت ( client ) ProtonVPN از IPv6 پشتیبانی نمیکنه. بهترین کار اینکه بیایم غیرفعالش کنیم تا از نشت اتفاقی IPv6 جلوگیری کنیم! برای اینکار فایل etc/sysctl.conf/ رو با هم ادیتوری که دوست دارید باز کنید ( من از nano استفاده میکنم )و این خطوط رو آخر فایل وارد کنید. net.ipv6.conf.all.disable_ipv6 = 1 
net.ipv6.conf.default.disable_ipv6 = 1 
net.ipv6.conf.lo.disable_ipv6 = 1 
net.ipv6.conf.tun0.disable_ipv6 = 1برای ذخیره CTRL + O رو بزنید و برای خروج CTRL + X.برای اینکه تغییرات هم اعمال بشه این دستور رو استفاده کنید.$ sudo sysctl -pعنوان دوست داشتنی: اتصالاول این دستور رو بزنید$ sudo protonvpn connectپلن رایگان ۳ تا کشور به ما میده :‌‌ ژاپن و هلند و آمریکاهر سه تاشون خوبن اما ما اینجا از کشور ژاپن استفاده کردیم! اینجا میتونید کشوری رو که میخواهید انتخاب کنید. ( پروتون با قصد این سه تا کشور رو انتخاب کرده چون تقریبا در دسترس همه افراد توی زمین هستن و لازم هم نیست که همه به یک سرور وصل بشن و اینطوری هر کسی به هر یک از این ۳ کشور نزدیک تره به اون وصل میشه )حالا سروری رو که دوست دارید انتخاب کنید.پروتوکل ارتباطی تون رو هم انتخاب کنید.اگر اتصال موفقیت آمیز باشه پیام connected نشون داده میشه.برای اثبات اینکه VPN وصل شده میتونیم برید به https://whatismyip.com و  آیپی مون رو چک کنیمبرای قطع اتصال هم این دستور ساده رو استفاده کنید.$ sudo protonvpn disconnectمسیری که واسه اتصال رفتیم یکمی بلند بود. برای اتصال به سریع ترین سرور میتونید از دستور زیر استفاده کنید.$ sudo protonvpn c -fمن حتی اون رو به vpn  و vpnd اصطلاحا alias کردم. برای اینکار فایل HOME/.bashrc$/ رو باز کنید و این دستور رو بهش اضافه کنید و وقتی ذخیره کردید دستور بعدی رو استفاده کنید. alias vpn=&amp;quotsudo protonvpn c -f&amp;quot
alias vpnd=&amp;quotsudo protonvpn d&amp;quot
$ source ~/.bashrcحالا برای اتصال vpn $ و برای قطع اتصال vpnd $ رو استفاده کنید :)امیدوارم که مطالب به دردتون خورده باشه.باقی پست های من رو هم از این زیر میتونید بخونیداسنپ ها در لینوکسچرا باید از اسنپ ها به خوبی استفاده کرد؟و یک رشته مقاله که در مورد سیستم بسته بندی دبیان اند:سیستم بسته‌بندی ابزار ها و اصول اساسی</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Sun, 08 Aug 2021 21:34:22 +0430</pubDate>
            </item>
                    <item>
                <title>چرا از اسنپ ها ( Snaps ) میشه به خوبی استفاده کرد؟</title>
                <link>https://virgool.io/@liewpl/whytousesnapswell-uhoccfvhyvsq</link>
                <description>سلامتوی مقاله اسنپ ها یه مقدمه راجع به اسنپ ها خوندیم.توی این مقاله بیاید بررسی کنیم که چرا از اسنپ ها استفاده کنیم.خود من بعد از آشنایی با اسنپ ها، یه مدتی هست که دارم ازشون استفاده میکنم، و اسنپ ها توی یه کلمه واقعاً خوبن هم از نظر آپدیت بودن اونها، هم اینکه روی لینوکس نصب میشن ( کلمه لینوکس رو اینجا به کار بردم چون مخصوص یک توزیع لینوکس نیستن و تا الان روی ۴۱ توزیعی که از systemd استفاده میکنن ( systemd-enabled) قابل نصب، مدیریت و اجرا شدن هست.)  هم از نظر امنیتی خیلی خوب طراحی شدن، هم میشه چندین نسخه از یک برنامه رو از کانال‌های اون کنار هم نصب کرد (parallel install ) (چیزی که مثلاً برای deb package ها امکان‌پذیر نیست اینکه بیایم نسخه های beta , stable مثلاً بسته vlc رو با هم روی سیستم داشته باشیم.) و یکی از مهم‌ترین ویژگی‌های اون ها اینکه بسته بندی، انتشار و نگهداری اونها خیلی راحت هست.حالا بیاید تا یکی یکی این‌هایی که اسم بردم رو بررسی کنیم.آپدیت بودن اسنپ هااسنپ ها به طور خودکار آپدیت میشن ( که البته میتونید این رو تغییر بدید)‌. این به شما این امکان رو میده که آخرین نسخه از اون نرم‌افزار رو نصب کنید و اصلاً هم نگران تعارض وابستگی‌ها ( dependency conflicts که توی control فایل‌ها میتونید اون ها رو پیدا کنید،) و یا نگران نبود وابستگی‌ها و پیش آمدن dependency hell نباشید، چون اسنپ ها از سیستم منزوی و یا isolate شدن و کاری به کار بقیه پکیج ها یا حتی دیگر اسنپ ها ندارن.آپدیت های اسنپ ها به طور automatic, transactional and atomic هست ( متأسفانه معادل و یا معنای خوبی پیدا نکردم اما این سه تا کلمه رو با هم الان توضیح میدم.) این یعنی اینکه اگر یک آپدیت برای یک اسنپ موفق نبود، ورژنی قبلی ای که روی سیستم بوده به کار کردن ادامه میده ( یعنی کارایی اش مختل نمیشه )‌ و این آپدیت مشکل دار ( buggy update )‌ به تعویق می‌افته و اون اپلیکیشن وقتی آپدیت میشه که توسعه دهنده یه نسخه جدید، بهتر و نسخه ای که کارکردن اش تأیید شده ارائه بده.به طور پیشفرض snapd هر روز ۴ بار چک میکنه که ببینه آیا آپدیتی فراهم هست یا نه، که به هر آپدیت یک refresh میگن.اما این رفتار رو میشه خیلی راحت عوض کردن و هر جوری که میخواید برنامه‌ریزی اش کردبرای مثال جوری تنظیم بشه که جمعه ها نصف شب آپدیت ها چک بشن یا اینکه سومین دوشنبه ماه یا آخرین جمعه ماه بین ساعات یازده شب تا یک صبح refresh انجام بشه.اطلاعات و راهنمایی های بی‌نظیری اینجا هست.امنیتاسنپ ها خیلی بیشتر از بسته های دیگه امنیت دارن! حالا چطور ؟ خب آپدیت های خودکار باعث میشن که مشکلات امنیتی خیلی زود برطرف بشن و از همه مهم تر اینکه اونها از بقیه سیستم شما منزوی ( isolate ) شدن. اون ها فایل سیستم (‌ file system ) مخصوص به خودشون رو دارن و نمیتونن با بقیه بسته ها و برنامه روی سیستم شما ارتباط بگیرن، حتی اگر هم شما یه برنامه ناشناس و مشکوک رو نصب کنید اون نمیتونه از فضای خودش فرار کنه. البته هیچ چیزی ۱۰۰٪ امن نیست اما استفاده از اسنپ ها یعنی شما بیشتر از قبل از سیستمتون نسبت به اون برنامه ها محافظت میکنید. (‌ البته توضیحاتی بیشتری برای این بخش نیازه که در ادامه اون ها رو باید بخونید.)برای اسنپ ها سه نوع حصر (‌ confinement ) وجود داره: سخت گیرانه  ( Strict )این حصر، حصر پیش‌فرض برای تمامی نرم افزار های اسنپ استور هست. این حصر تنها اجازه خواندن و نوشتن (‌ read and write ) در پوشه نصبی و قسمتی که برای اون برنامه در پوشه یا پارتیشن home هست رو به برنامه میده.حصر سخت گیرانه اجازه خواندن و نوشتن رو فقط در این آدرس ها به برنامه میدهمسیر هایی که در حصر سختگیرانه به برنامه اجازه خواندن و نوشتن داده می‌شود.۲.   حالت توسعه ( Devmod )این حصر توسط توسعه دهنده ها استفاده میشه تا برنامه شون رو تست کنن. اسنپ هایی که در این حصر هستن نمیتونن به عنوان یک نسخه پایدار ( stable ) منتشر بشن و برای اینکه بتونن منتشر کنن باید به strict یا classic تغییر پیدا کنن و از کانال های پایدار (‌ stable ) یا کاندید ( candidate ) منتشر بشن.۳.  حالت کلاسیک ( classic )اسنپ های کلاسیک دقیقا مثل پکیج های دبیان رفتار میکنن و به سیستم شما دسترسی دارن و مثل اون ها میتونن به پوشه های روت ( root folders ) دسترسی خواندن و نوشتن بدون هیج حصر و محدودیتی داشته باشن.با اینکه برنامه های میتونن همچنین حصر بی حصری :)‌  داشته باشن اما این به این معنی نیست که همه میتونن برنامه ای با این دسترسی ها منتشر کنن.اگر برنامه ای بخواد با این حصر منتشر بشه باید توسط یک تیم در snapcraft.io بعد از اینکه دلایل توسعه دهنده برای این حصر توسط همه اعضای اون تیم تایید شد، تایید بشه و بعد از این جریان اجازه انتشار به اون برنامه با حصر کلاسیک داده میشه.کانال هاساخته شده توسط گوگل کروم ( و الان هم گوگل پلی استور ،)‌ اسنپ ها هم از کانال ها پشتیبانی میکنن. اسنپ ها این اجازه رو به شما میدن که ورژن های متفاوت یک نرم افزار رو نصب کنید و حتی بعد از نصب هم میتونید کانالی که نرم افزار از اون نصب شده رو تغییر بدید برای مثال از استیبل برید روی کانال بتا.نصب های موازیحتی بیشتر از این امکان که شما میتونید از کانال های متفاوتی برنامه تون رو نصب ( یا اگر توسعه دهنده هستید، منتشر ) کنید، شما میتونید ورژن های متفاوتی از یک اسنپ رو به صورت موازی روی سیستم‌تون نصب کنید. از اونجایی که هر اسنپ از سیستم منزوی هست، استفاده کنندگان این آزادی رو دارن که ورژن های مختلف رو بدون هیچ دردسر یا اختلال یا حتی از دست دادن داده روی سیستم نصب و اجرا کنن.بسته بندی، انتشار و نگهداری راحتتوسعه دهندگان میتونن از سرویسی که توسط شرکت .Canonical Ltd فراهم اومده به صورت رایگان استفاده کنن و برنامه شون رو خیلی ساده توسعه، بسته بندی ، منتشر و نگهداری کنن. اما این چه ربطی به استفاده کنندگان داره؟! خیلی از نرم افزار های غیر متن باز و غیر آزاد ( proprietary )( نتونستم معادل یا معنی خوبی براش پیدا کنم )( یا حتی برخی از متن باز ها) برای لینوکس بسته ای ارائه نمیدن، یا با توجه به اینکه توزیع های مختلفی وجود داره و بازار اپ های لینوکسی تکه تکه شده یا یه بسته برای یک توزیع ( برای مثال اوبونتو ) ارائه میدن یا کلا هیچی. اما اسنپ ها رو میشه خیلی راحت ساخت و اون های برای خیلی از توزیع ها منتشر و قابل استفاده کرد. برای مثال اپ های Slack, Spotify, Skype, Discord الان خیلی ساده در اختیار کاربران لینوکسی هستن :)امکانات اسنپ ها در یک نگاهبسته بندی ساده با استفاده از ابزار های موجود شما.آپدیت های خودکار ( و قابل مدیریت ) برای تمام یوزر ها.داشتن مخاطب میلیونی کاربران لینوکس ( تقربیا تا ۹۹٪‌ distro-independent ).قابلیت برگرداندن ورژن بدون زحمت.داشتن کانال های متفاوت نصب.قابلیت نصب موازی یک اسنپ روی یک سیستم.سرویس snapshot.آزاد و رایگان برای پروژه های متن باز و متن بسته.نصب خیلی ساده اسنپ ها توسط Software center ها و ترمینال.اسنپ ها امن هستن، چون محصور اند و به سیستم، دیگر برنامه ها و داده های شما دسترسی ندارن.و ...جمع بندیاسنپ های مزایای بسیاری نسبت به مثلا deb package ها دارن ( البته نواقصی هم دارن و به هیچ وجهی نمیشه گفت حتما این یا حتما اون ) برای مثال امنیت و آپدیت های اونها.با اسنپ ها شما میتونید نرم افزار های بروز داشته باشید چون اون ها با کتابخانه ها و پیشنیاز های خودشون پیش هم هستن و کاری به بقیه سیستم ندارن.با پشتیبانی از آپدیت های transactional ( معادل اش میشد معامله ای :| ) این امکان رو میدن که موقع آپدیت فقط قسمت هایی که تغییر کردن دانلود بشن.شما میتونید برنامه تون رو راحت توسعه بدید و منتشر کنید.و ...برگرفته از :A technical comparison between snaps and debsWhat Are Linux Snap Packages? Why Use Them?.snap Vs .deb PackageManaging updatesامیدوارم تونسته باشم اطلاعات خوبی ارائه بدم. ممنون که وقت گذاشتید.</description>
                <category>مهدی</category>
                <author>مهدی</author>
                <pubDate>Fri, 06 Aug 2021 14:59:00 +0430</pubDate>
            </item>
            </channel>
</rss>