پایتونیک - آشنایی با String formatting

مقدمه

سلام. امروز می خوایم یه سری به رشته‌ها توی پایتون بزنیم. توی قسمت اول مجموعه پایتونیک گفتیم اصطلاحاً به کدی پایتونیک گفته میشه که خوانا‌ترین و مرسوم‌ترین شیوه استایل کد برای اون کد استفاده شده باشه. اما واقعاً بعضی مواقع بیش از یک راه‌حل واسه انجام یک کار وجود داره. یکی از این جور مواقع،‌ String Formatting توی پایتون هست. منظورم از String Formatting اینه که بخوایم یک سری متغییر رو توی یک رشته جایگذاری کنیم. توی این پست می‌خوام تمام راه‌های ممکن رو بررسی کنیم و به یک جمع بندی برسیم که کدوم راه‌حل برای چه موقعی مناسب هست.

برای این‌که بررسی این روش‌ها راحت بشه، فرض می‌کنیم که متغییر‌های پایین رو داریم:

errno=1528385098
name = "Admin"

و هدفمون اینه که با روش‌های مختلف بتونیم به خروجی زیر برسیم: در حقیقت اسم کاربر و همین‌طور شماره خطا به صورت هگزادسیمال چاپ کنیم:

'Hey Admin, there is a 0x5b194e4a error!'

قدیمی‌ترین روش - C style

اگه با با زبان‌های سی و سی‌پلاس‌پلاس کار کرده باشید حتما به تابع printf برخوردید،‌ اگر هم استفاده نکردید یه دستور printf توی سیستم‌های یونیکسی هست که دقیقا مشابه همون کار رو میکنه(مثال). خب بریم ببینیم این‌کار توی پایتون به چه صورته؟
توی مثال پایین یک رشته داریم و یه متغییر که جای اون توی توسط کاراکتر % رزرو شده. اما اگه سواله واستون که s بغلِ % چیه، همونطور که قابل حدسه داره میگه که یک رشته(string) قراره اینجا جایگذاری بشه.

>>> "Hey %s" %name
Output:
Hey Admin

به جای s کاراکتر‌های دیگه رو با کاربرد‌های دیگه هم میشه استفاده کرد. مثلا بهش بگیم شماره خطا رو به صورت هگزادسیمال جایگزین شه:

>>> "The error number is 0x%x" %errno
Output:
The error number is 0x5b194e4a

اگه بخوایم از چند متغییر همزمان استفاده کنیم چی؟ بعد از stringایی که نوشتیم و علامت %یک پرانتر باز و بسته می‌ذاریم و داخل اون به تعداد %ها باید بهش مقدار متناظر با اونارو بدیم. مثلاً:

>>> 'Hey %s, there is a 0x%x error!' %(name, errno)

اما ایرادی که میشه به کد بالا گرفت اینه که این کد خیلی خوانا نیست و همه‌اش نیاز دارید بگردید ببینید کی قراره با چی جایگزین شه. اما خب باید گفت که میشه یکم روش بالا رو خواناتر کرد، ببنیم با هم:

>>> 'Hey %(name)s, there is a 0x%(errno)x error!' % {
... "name": name, "errno": errno }

خُب، همون‌طور که می‌بینید اول از همه برای بعد از هر % یک اسم بهشون اختصاص دادیم و بعد از اون با کمک یک دیکشنری مشخص کردیم که اون اسم‌ها با کدوم متغییر جایگزین شَن. اینجوری کدمون خواناتر شده که باعث میشه خیلی راحت‌تر بشه از کد نگه‌داری کرد و تغییرات آینده رو با سهولت بیشتری اعمال کرد. ولی میشه ایراد‌هایی هم بهش گرفت مثلاً اینکه خیلی بنظرِ من شبیه ‌کدهای پایتون نیست. دوم اینکه تکرار اسم متغییر توی اون خیلی زیاده توی مثال بالا سه بار نوشتیم name.

اولین ناجی - تابع format

طبیعی هست که انتظار داشته باشیم دوستان توسعه دهنده پایتون تلاش‌هایی برای بهتر کردن پایتون توی این زمینه کرده باشند. اولین تلاش توی پایتونِ نسخه‌ی 3 معرفی شد، که در حقیقت ارائه تابعی به نام format روی داده‌های از نوعِ String بود. بدون توضیح اضافه بریم سراغ یک مثال:

>>> "Hey {}".format(name)

اینجا دیگه به جای % از {} استفاده شده که هر کجا که یه دونه {} گذاشتیم جلوتر باید مشخص که قرار جای اون چه چیزی قرار بگیره و این کار توی یک متدی به اسم format صورت میگیره.
اما اگه بخوایم هم چند متغییر بدیم و هم اینکه بخوایم برای هر کدومش اسمی مشخص کنیم که خوانا باشه، این شکلی میشه:

>>> 'Hey {name}, there is a 0x{errno:x} error!'.format(
... name=name, errno=errno)

طبیعی هست که انتظار داشته باشیم همه کار‌هایی که توی حالت قدیمی انجام میشد اینجا انجام بشه و همین‌طور بشه کار‌ها رو اینجا خیلی راحتتر انجام داد. برای اطلاعات بیشتر به مستنداتش رجوع کنید.

این روش نسبت به روش اول بهتره ولی گند کار اونجا در میاد که متغییراتون زیاد بشه، اون موقع میبینید، چقدر کدِ پیچیده‌ای میشه!

پایتون ۳.۶ و ‌F-Strings‌ باحال

یک روشی که توی نسخه پایتون 3.6 معرفی شد، که با اسم f-strings میشناسیمش و هر موقع که می‌خوایم ازش استفاده کنیم کافیه یک f قبلِ رشتمون بذاریم و از متد format یه‌جورایی بی‌نیاز شدیم، ایندفعه مستقیم داخل {} اسم متغییر رو می‌نویسم، که بنظر من خیلی فوق‌العادس! یعنی اینجوری:

>>> f"Hey {name}"
>>> f'Hey {name}, there is a 0x{errno:x} error!'
  • یادتون باشه داخل {} همه نوع کاری مثل انجام کار‌های محاسباتی جمع، تفریق کد پایتون و ... میشه انجام داد و شاید براتون جالب باشه که بدونید سرعت این روش از دو روش بالا هم بیشتره!
  • تنها ایرادی که میشه به این روش گرفت اینِ که شما حتما باید پایتون 3.6 داشته باشید تا بتونید ازش استفاده کنید.

منابع بیشتر

  • معرفی کامل f-strings از سایت خیلی خوبِ RealPython
  • این دوست خوبمون هم یک کلیپ آموزشی در این رابطه گذاشته، که بنظرم خیلی هم خوبه کلی مثال داره که تکمیل کننده لینک بالا هست، لینک

ماژولِ ناشناخته‌ی string

آخرین چیزی که راجعبش صحبت می‌کنیم ماژول string هست که یکی از ماژول‌های قدیمی پایتون به حساب ‌میاد و اکثر متد‌هایی که داشته الان منتقل شدند به داده‌های string اما یه چند تا کلاس داره که توی همین‌ماژول فقط هستند، من‌جمله کلاسِ Template. توی این لینک یک معرفی جامع از این ماژول و کاربرد‌هاش داریم. من فقط یک مثال ازش مطابق مساله خودمون می‌زنم و بقیه‌اش میمونه به عهده‌ خودتون.

مثال:

>>> from string import Template
>>> my_template = Tempalte('Hello $name')
>>> my_template.substitute(name=name)

همونطور که میبیند یک کار دو مرحله‌ای هست و نیاز به اجرای متد substitute هم هست. یک نقطه ضعف این روش عدم وجود چیزهای هست که بشه باهاش عددمون رو به هگزادسیمال نشون بدیم یا چیز‌های مشابه این، یعنی این‌کار رو دستی باید انجام بدیم. میگن که بهترین موقع برای استفاده از این ماژول وقتی هست که قرار هست یک رشته از کاربر گرفته بشه و چون این رشته‌ها ممکن حاوی هر نوع کاراکتری باشه که برنامه و یا سیستم رو بشکنه بهتر است که از این ماژول برای این قبیل از کار‌ها استفاده بشه.

نتیجه‌گیری

این صحبت‌ها، بیشترش از لینکی بود که پایین میذارم و هدفم فقط اضافه کردم توضیحات خودم به این مطالب، برای پایتون کار‌های فارسی زبان، بود. اما به عنوان جمع‌بندی تا الان باید به این نتیجه رسیده باشیم، که‌ اگه دنبال این هستیم که خیلی پایتونیک و شیک کد بزنیم با پایتون حداقل باید شیوه قدیمی string formatting رو کنار بگذاریم (C style).

در بقیه موارد اگه دوست ندارید که کد خودتون رو محدود به پایتون 3.6 کنید از تابع format استفاده کنید. ولی اگه لزومی نمی‌بینید که از نسخه‌های قدیمی پایتون پشتیبانی کنید حتما از f-strings استفاده کنید که واقعاً چیز باحالیه.

و نکته نهایی اینکه اگر چیزی از کاربر می‌گیرید که امکان inject کردن کد مشکوک یا مسیر‌های غیرمجاز توی سیستم‌تون توسط کاربر رو میدین، حتماً برید سراغ ماژولِ string. خلاصه این صحبت‌ها توی شکل پایین اومده. امیدوارم که از این قسمت خوشتون اومده باشه.

لینک به سایت اصلی
لینک به سایت اصلی

لینک مراجع

  • https://realpython.com/python-string-formatting/