
حتما تا کنون چنین دفترچه هایی را در مغازه ها دیده اید. در این دفترچه، چیز هایی که بین همه خرید ها یکسان است از پیش نوشته شده است و اطلاعاتی که متناسب با هر خرید متغیر است خالی قرار داده شده تا فروشنده پر کند. هدف این دفترچه افزایش سهولت و سرعت صدور فاکتور است.
در برنامهنویسی نیز گاهی لازم داریم تا الگو های مشابهی در متن ها داشته باشیم. بدین ترتیب قسمت هایی که بین همه الگو ها یکسان است را به عنوان یک قالب تعریف کرده و قسمت هایی که متغیر هستند را با استفاده از string formatting مقدار دهی میکنیم.
Old-style string formatting
روش قالببندی رشته با عملگر % که به Old-Style String Formatting معروف است، از همان نسخههای اولیه پایتون و بهطور مشخص از Python 1.0 معرفی شد. این روش که الهامگرفته از تابع printf در زبان C است، با استفاده از مشخصکنندههایی مانند %s و %d و %f مقادیر متغیرها را داخل رشته جایگزین میکند. با وجود اینکه این شیوه هنوز در پایتون پشتیبانی میشود، امروزه به دلیل خوانایی کمتر، احتمال بروز خطا و محدودیت در قالببندیهای پیچیده، برای کدنویسیهای جدید توصیه نمیشود و جای خود را به روشهای مدرنتری مانند str.format و f-string داده است.
چرا باید یادش بگیریم؟
شاید لازم شود کدی که سالها پیش نوشته شده را بخوانید. در این صورت احتمال دارد چنین سینتکسی به چشم تان بخورد. به همین دلیل بهتر است با آن آشنا باشید.
سینتکس چیست؟
به قوانین و دستور زبانِ یک زبان برنامهنویسی، سینتکس (syntax) میگویند.
Single Positional Placeholders
یا به صورت دقیق تر، single old-style positional formatting روشی است که برای جایگذاری تنها یک مقدار در یک رشته استفاده میشود.
name = "John"
formatted_string = "My name is %s." % name
print(formatted_string) # خروجی: "My name is John ."
Multiple Positional Placeholders
یا به صورت دقیق تر، Multiple old-style positional formatting روشی است که برای جایگذاری چندین مقدار در یک رشته استفاده میشود.
name = "John"
age = 30
formatted_string = "My name is %s and I'm %d years old." % (name, age)
print(formatted_string) # خروجی: "My name is John and I'm 30 years old."در کد بالا، ۲ تا جای خالی تعریف کردهایم.
- اولین جای خالی را با
%sتعریف کرده ایم بدین معنی که قرار است یک رشته در این قسمت جایگذاری شود. (s اولین حرف string است) - دومین جای خالی را با
%dتعریف کرده ایم بدین معنی که قرار است یک عدد در این قسمت جایگذاری شود. (d اولین حرف digit است)
برای جایگذاری یک عدد در یک رشته، هم از %s و هم از %d و هم از %f میتوان استفاده کرد ولی بهتر است از %d برای اعداد صحیح و از %f برای اعداد اعشاری استفاده شود زیرا این عملگر ها امکاناتی برای اعداد ارائه میدهند که %s آن امکانات را ندارد.
در کد بالا، دقیقا ۲ بار از علامت % برای مشخص کردن جای خالی استفاده شده و دقیقا ۲ مقدار نیز در پرانتز به رشته ارسال کرده ایم. اگر تعداد % ها با مقادیری که به رشته ارسال میشود برابر نباشد با خطا مواجه خواهیم شد.
Named Placeholders
روش های قبلی در برخی حالات پیچیده میشوند. به تکه کد زیر توجه کنید.
product = "Laptop"
price = 1250
buyer = "Ali"
seller = "TechStore"
discount = 150
final_price = price - discount
warranty_years = 2
report = (
"Purchase Report:\n"
"Buyer: %s\n"
"Seller: %s\n"
"Product: %s\n"
"Original Price: %d USD\n"
"Discount: %d USD\n"
"Final Price: %d USD\n"
"Warranty: %d years\n\n"
"Summary:\n"
"%s purchased a %s from %s. The original price was %d USD but after a "
"discount of %d USD, the final cost became %d USD. The product includes "
"%d years of warranty.\n"
) % (
buyer, seller, product, price, discount, final_price, warranty_years,
buyer, product, seller, price, discount, final_price, warranty_years
)
print(report)کد بالا مشکلات زیر را دارد:
- مثلا پیدا کردن متغیری که مقدار %d را در خط ۱۸ پر میکند سخت است.
- در خط ۲۳ و ۲۴ برخی از متغیر ها چندین بار تکرار شده اند. این تکرار بیهوده است و خوانایی را کاهش میدهد.
- اگر یکی از متغیر هایی که در خط ۲۳ و ۲۴ نوشته شده است، ترتیبشان تغییر کند خروجی برنامه بدون اینکه خطایی رخ دهد اشتباه میشود. این یعنی این روش باعث شده تا استیبل بودن این کد کاسته شده و احتمال باگ خیز بودن افزایش پیدا کند.
راه حل این مشکل، استفاده از Named Placeholders یا به صورت دقیق تر، Old-Style Named Placeholders است.
product = "Laptop"
price = 1250
buyer = "Ali"
seller = "TechStore"
discount = 150
final_price = price - discount
warranty_years = 2
data = {
"buyer": buyer,
"seller": seller,
"product": product,
"price": price,
"discount": discount,
"final_price": final_price,
"warranty": warranty_years
}
report = (
"Purchase Report:\n"
"Buyer: %(buyer)s\n"
"Seller: %(seller)s\n"
"Product: %(product)s\n"
"Original Price: %(price)d USD\n"
"Discount: %(discount)d USD\n"
"Final Price: %(final_price)d USD\n"
"Warranty: %(warranty)d years\n\n"
"Summary:\n"
"%(buyer)s purchased a %(product)s from %(seller)s. The original price was "
"%(price)d USD but after a discount of %(discount)d USD, the final cost became "
"%(final_price)d USD. The product includes %(warranty)d years of warranty.\n"
) % data
print(report)امکانات مخصوص اعداد
نمایش عدد صحیح
برای نمایش عدد صحیح بهتر است از %d استفاده شود.
age = 25
print("Age: %d" % age)
# Output: Age: 25نمایش عدد اعشاری
برای نمایش اعداد اعشاری بهتر است از %f استفاده شود.
pi = 3.14159
print("Pi value: %f" % pi)
# Output: Pi value: 3.141590تعیین تعداد رقم اعشار
در این کد با تعریف .2 عدد اعشاری را تا دو رقم نمایش داده ایم.
print("Pi value: %.2f" % pi)
# Output: Pi value: 3.14تعیین عرض عدد
نمایش اعداد با استفاده از کد زیر خوانایی خوبی ندارد زیر یکان و دهگان و هزارگان هر کدام، زیر یکدیگر قرار ندارند.
print(1)
print(20)
print(300)
print(4)
print(50)
print(6000)
# Output:
# 1
# 20
# 300
# 4
# 50
# 6000اکنون با استفاده از کد زیر، میتوانیم یک نظم خوبی به نوع نمایش آنها بدهیم.
print("%5d" % 1)
print("%5d" % 20)
print("%5d" % 300)
print("%5d" % 4)
print("%5d" % 50)
print("%5d" % 6000)
# Output:
# 1
# 20
# 300
# 4
# 50
# 6000عدد 5 که بین % و d قرار گرفته است، میگوید که طول عدد به همراه فاصله های قبلش باید ۵ واحد شود. یعنی اگر عدد تک رقمی باشد، ۴ تا فاصله و اگر عدد دو رقمی باشد، ۳ فاصله و … قبل از آن اضافه میکند تا این فرمت خوانا ایجاد شود.
New-style string formatting
روش قالببندی رشته با استفاده از str.format() که با عنوان New-Style String Formatting شناخته میشود، بهصورت رسمی با معرفی Python 3.0 وارد زبان پایتون شد. این روش امکان جایگذاری مقادیر درون رشتهها را با استفاده از آکولادها ({}) فراهم میکند و نسبت به روش قدیمی % خواناتر، منعطفتر و قدرتمندتر است. این شیوه در PEP 3101 معرفی شد و بهعنوان جایگزین رسمی روش قدیمی قالببندی رشتهها در پایتون مطرح گردید و تا پیش از معرفی f-stringها در PEP 498، روش استاندارد و توصیهشده برای قالببندی رشتهها بهشمار میرفت.
مثال زیر یک نمونه ساده از کاربرد این تابع است.
name = "Mohammadreza"
age = 30
formatted_string = "My name is {} and I'm {} years old.".format(name, age)
print(formatted_string) # خروجی: "My name is Mohammadreza and I'm 30 years old."در مثال بالا، اولین ورودی در موقعیت اولین آکولاد و دومین ورودی در موقعیت دومین آکولاد قرار میگیرد.
اکنون به مثال زیر توجه کنید.
name = "Mohammadreza"
age = 30
formatted_string = "His name is {} and He's {} years old. {} is a programmer".format(name, age, name)
print(formatted_string)
# Output: His name is Mohammadreza and He's 30 years old. Mohammadreza is a programmerمشکلی که در مثال بالا داریم این است که نام را دو بار در تابع فرمت استفاده کرده ایم. برای اینکه کد بالا کمی خوانا تر شود میتوان آن را به شکل زیر بهبود داد.
name = "Mohammadreza"
age = 30
formatted_string = "His name is {0} and He's {1} years old. {0} is a programmer".format(name, age)
print(formatted_string)
# Output: His name is Mohammadreza and He's 30 years old. Mohammadreza is a programmerعدد صفر به اولین ورودی format و عدد یک به دومین ورودی آن اشاره میکند. اکنون از شما میخواهم به این فکر کنید که اگر ابتدا age و سپس name را به format پاس میدادیم چه اعدادی در آکولاد ها باید مینوشتیم که خروجی همچنان به درستی کار میکرد؟
پاسخ این سوال را در تکه کد زیر ببینید.
name = "Mohammadreza"
age = 30
formatted_string = "His name is {1} and He's {0} years old. {1} is a programmer".format(age, name)
print(formatted_string)
# Output: His name is Mohammadreza and He's 30 years old. Mohammadreza is a programmerاگر تعداد ورودی هایی که به format ارسال میکنید زیاد بود، برای حفظ خوانایی کد از روش زیر استفاده کنید.
name = "Mohammadreza"
age = 30
formatted_string = "His name is {name} and He's {age} years old. {name} is a programmer".format(name=name, age=age)
print(formatted_string)
# Output: His name is Mohammadreza and He's 30 years old. Mohammadreza is a programmerکد بالا را با استفاده از دیکشنری هم میتوان نوشت. این روش بیشتر زمانی کاربرد دارد که مقدار متغیر args به طریقی خودش پر خواهد شد و شما صرفا نیاز است تا آن را به تابع format ارسال کنید.
args = {
"name": "Mohammadreza",
"age": 30
}
formatted_string = "His name is {name} and He's {age} years old. {name} is a programmer".format(**args)
print(formatted_string)
# Output: His name is Mohammadreza and He's 30 years old. Mohammadreza is a programmerکار با اعداد
تعیین تعداد رقم اعشار
print("{:.2f}".format(3.14159))
# Output: 3.14تعیین عرض عدد
print("{:5d}".format(42))
# Output: 42تراز عدد در عرض مشخص از چپ
print("{:<5d}".format(42))
# Output: 42 تراز عدد در عرض مشخص وسط
print("{:^5d}".format(42))
# Output: 42 تراز عدد در عرض از راست
print("{:>5d}".format(42))
# Output: 42پر کردن فضای خالی با کارکتر دلخواه
print("{:0>5d}".format(42))
# Output: 00042جداکننده هزارگان
print("{:,}".format(1000000))
# Output: 1,000,000نمایش عدد اعشاری به صورت درصدی
print("{:.1%}".format(0.875))
# Output: 87.5%F-strings
f-string که مخفف Formatted String Literal است، روشی برای قالببندی رشتههاست که در آن میتوان متغیرها و حتی عبارات پایتونی را مستقیماً داخل رشته قرار داد. این قابلیت از Python 3.6 به بعد اضافه شده است.
name = "John"
age = 30
formatted_string = f"My name is {name} and I'm {age} years old."
print(formatted_string) # خروجی: "My name is John and I'm 30 years old."یکی از قدرتهای f-string امکان استفاده از محاسبات و توابع است.
x = 10
y = 3
print(f"جمع: {x + y}")
print(f"توان: {x ** y}")حتی میتوان یک تابع را مستقیم در آن فراخوانی کرد.
def say_hello(name):
return f"hello {name}"
print(f"{say_hello('Amir')}")کار با اعداد
تعیین تعداد رقم اعشار
value = 3.14159
print(f"{value:.2f}")
# Output: 3.14تعیین عرض عدد
value = 42
print(f"{value:5d}")
# Output: 42تراز عدد در عرض مشخص از چپ
value = 42
print(f"{value:<5d}")
# Output: 42 تراز عدد در عرض مشخص از وسط
value = 42
print(f"{value:^5d}")
# Output: 42 تراز عدد در عرض مشخص از راست (پیش فرض)
value = 42
print(f"{value:>5d}")
# Output: 42پر کردن فضای خالی با کارکتر دلخواه
value = 42
print(f"{value:0>5d}")
# Output: 00042جدا کننده هزارگان
value = 1000000
print(f"{value:,}")
# Output: 1,000,000نمایش عدد اعشاری به صورت درصدی
value = 0.875
print(f"{value:.1%}")
# Output: 87.5%حفظ نکنید!
در این بخش با انواع زیادی از string formatting آشنا شدید. هیچکدام را حفظ نکنید. فقط در حدی بلد باشید که اگر کدشان را دیدید تعجب نکنید.