یک کارگاه پوشاک در اردبیل هر ماه یک فایل CSV از خریدهایش دارد و میخواهد بداند از هر تامینکننده چقدر گرفته است. یازده سطر، بدون نصب هیچ چیزی، و خروجی این است:
{'Sepehr': 37, 'Aria': 47}- و در پایگاه داده:
[('Aria', 47), ('Sepehr', 37)]
کل ماجرا پنج ایمپورت است و یک حلقه. Path("kargah").glob("mah_*.csv") فایلهای ماهها را پیدا میکند بدون آنکه اسمشان جایی نوشته شده باشد، و همان شی هم باز میکند، هم مسیر میسازد، هم وجود داشتنش را بررسی میکند. csv.DictReader برای هر سطر یک دیکشنری میدهد که کلیدهایش سطر عنوان است، پس r["tedad"] کار میکند بدون شمردن ستونها. Counter کلید تازه را خودش با صفر شروع میکند، پس آن دو سطر مراقبتی که همه اول مینویسند لازم نیست. و sqlite3.connect یک پایگاه داده واقعی داخل خود مفسر باز میکند، بدون هیچ سروری.
یک سطر کار بیصدا انجام میدهد: if not r["tedad"]: continue رشته خالی را رد میکند که یک خانه پرنشده در CSV به جا میگذارد، چون خانه خالی از CSV بهشکل رشته خالی میرسد و هرگز بهشکل None. اگر جا بیفتد، int روی رشته خالی برنامه را متوقف میکند، که رایجترین اولین خرابی چنین اسکریپتی است.
و یک جزئیات در خروجی هست که ارزش دیدن دارد: statistics.median روی دو مقدار میانگینشان را میدهد، پس نوع نتیجه اعشاری میشود و اندازه میانه سفارشهای سپهر ۱۸٫۵ چاپ میشود. هیچ چیز خراب نیست؛ تابع دارد میگوید چند تا داده داشته.
در ایران، کتابخانه استاندارد دو برابر میارزد
هیچکدام از موارد بالا از یک بسته بیرونی نیامد. csv و pathlib و collections و statistics و json و sqlite3 با خود مفسر میآیند، با آن نسخهگذاری میشوند، و برای اینکه به هم داده شوند نوشته شدهاند. تاریخ، درخواست HTTP، فایل زیپ و یک اجراکننده آزمون هم با همان شرایط داخلشان هستند. دانستن اینکه چه چیزی از قبل هست، تفاوت یک اسکریپت یازده سطری با پروژهای است که فایل وابستگی دارد، و موضوع چه چیزی همراه پایتون میآید و یک وابستگی را از شما کم میکند است.
این حساب همهجا درست است و اینجا دو برابر میارزد، چون هر وابستگی تازه از ایران یک مسئله گمرکی است نه یک دستور. اسکریپت بالا روی هر ماشینی که پایتون دارد اجرا میشود، بدون شبکه و بدون تنظیم آینه. نسخهای از همین اسکریپت که با یک کتابخانه دیتافریم شروع شود، یک وابستگی کامپایلشده، یک قید نسخه و یک دلیل برای اهمیت دادن به اینکه کدام مفسر روی مسیر است با خودش میآورد.
نحوِ زیر همه اینها واقعاً کوچک است: تورفتگی بلوک را نگه میدارد، آکولاد و سمیکالنی در کار نیست، و یک تازهکار یک صفحه از آن را میخواند پیش از آنکه چیزی یادش داده باشند. همین خوانا بودن دلیل این است که اول به دست همه داده میشود، و نحو، نوعها و اصطلاحهای رایج است. همین هم دلیل این است که آدمها باقی ماجرا را دست کم میگیرند.
باقی ماجرا محیط است، و بیشتر آن دو هفته همین است
اسکریپت اجرا میشود. اسکریپت روی لپتاپ نویسندهاش اجرا میشود. فاصله میان این دو جمله همان هفته دوم است و هیچکدامش پایتون نیست. python3 -m venv .venv برای هر پروژه مفسر و بستههای خودش را میسازد، که تنها حرکتی است که جلوی خراب شدن یک پروژه با ارتقای پروژه دیگر را میگیرد. بدون آن هر نصب سراسری است و هر پروژه سر یک مجموعه نسخه با بقیه دعوا دارد.
فایل قفل نسخههای دقیق را ثبت میکند و جایش داخل مخزن است، چون فهرستی از نامها بدون نسخه، هر چیزی را که روز کلون شدن تازهتر است بازتولید میکند نه آن چیزی را که شما داشتید.
یک سطر دیگر هم جای هر فایلی است که ممکن است ایمپورت شود: if __name__ == "__main__" کدی را نگه میدارد که نباید موقع ایمپورت اجرا شود. فایلی بدون آن، وقتی چیزی ایمپورتش میکند کارش را انجام میدهد، و خرابیاش گیجکننده است چون آن ایمپورت ممکن است اجراکننده آزمون باشد یا فرایندی که یک کارگر را بالا میآورد. محیط و نصب و ابزارهای دورشان pip و venv، و جدا نگه داشتن پروژهها هستند.
هفته دوم
چه چیزهایی باید نگه دارند تا اسکریپت روی ماشین دیگری اجرا شود
هر حلقه تمام بار را میکشد، و آنکه پاره میشود هیچوقت همانی نیست که کسی درسش را خوانده.
- خود فایلیازده سطر، و تنها بخشی که اصلاً درس داده شده بود
- نسخه مفسردو نسخه عقب، روی ماشینی که کسی ارتقایش نداده
- محیط پروژهیک venv، وگرنه همه پروژهها سر یک مجموعه بسته دعوا دارند
- فایل قفلنسخههای دقیق، وگرنه هر چه روز کلون شدن تازهتر باشد
- دسترسی به مخزن بستهو از ایران، آینهای که تنظیم شده باشد
حلقه باز همان جایی است که پروژه یک تازهکار واقعاً پاره میشود، و تنها حلقهای است که درست کردنش پیش از پاره شدن هیچ خرجی ندارد.
ابزار، و سالی که این حرف درست است
نسخه جاری پایتون در سال ۲۰۲۶ نسخه 3.14 است. uv که از سال ۲۰۲۴ آمده اولین چیزی است که باید نصب شود: رایگان و متنباز، و جای pip و virtualenv و pyenv را گرفت که سه ابزار بودند برای یک کار. نسخه مفسری را که پروژه میخواهد خودش نصب میکند و فایل قفل را مینویسد، یعنی همان پاراگراف بالا را حل میکند بهجای اینکه توضیحش بدهد. Ruff هم قالببند و بازرس است، از همان سازندگان، رایگان، و جای flake8 و isort و black را گرفت. هر دو یک فایل اجراییاند و هیچکدام برای اجرا شدن به پایتون خودشان نیاز ندارند، که همان مسئله دوری بود که توضیح ابزارهای قدیمی را دردناک میکرد.
برای ایران یک تنظیم به هر دو اضافه میشود و بهتر است یک بار انجام شود نه هر بار: نشانی آینه در فایل پیکربندی pip مینشیند و uv هم متغیر محیطی خودش را برای همین دارد. کدام آینه، چیزی است که تیمها برای خودشان انتخاب میکنند و روی این صفحه نامش را نمیآوریم، چون آن یکی چیزی است که سال به سال عوض میشود و ابزارها نمیشوند.
اشتباه: دست بردن به سمت یک بسته پیش از باز کردن کتابخانه
جایی که آدمها روی این زبان میایستند نه نحو است و نه دقیقاً محیط. این است که مسئلههای محیط بیشتر بهعنوان نتیجه یک وابستگی میرسند، و آن وابستگی معمولاً لازم نبوده. اسکریپتی که یک فایل جدولی میخواند، عددها را جمع میزند و خلاصهای چاپ میکند، یازده سطر کتابخانه استاندارد است.
قاعدهای که هیچ خرجی ندارد: پیش از نصب هر چیزی، یک بار کتابخانه استاندارد را برایش بگردید. جواب آنقدر «نه» درمیآید که عادت صادق بماند، و آنقدر «بله» که آن دو هفته را نجات بدهد. تلاش اول همان کارگاه با یک بسته صفحهگسترده و یک نصب شکستخورده شروع شد، و یازده سطر بالا چیزی است که از تلاش دوم باقی ماند.
پرسشی که این صفحه جواب نمیدهد این است که وقتی اسکریپت باید به کس دیگری جواب پس بدهد پایتون به چه درد میخورد، و دو راه دارد: همان کتابخانه استاندارد که به سمت کارهای خستهکننده نشانه رفته، در فایلها، صفحهگستردهها و کارهای خستهکننده، یا درخواستی که از بیرون میرسد، در جنگو، فلسک، و پاسخ دادن به یک درخواست. اینکه اصلاً کدام زبان ارزش آن دو هفته را دارد زیر زبانهای برنامهنویسی است، و اگر کد باید داخل مرورگر اجرا شود انتخاب از قبل گرفته شده و جاوااسکریپت است. مفسری هم که همه اینها را اجرا میکند کد چطور اجرا میشود.