แต่เดิมทีเวลาที่ต้องการจัดรูปแบบการแสดงผลของสายอักขระในไพธอนจะใช้รูปแบบการเขียนโดยใช้ % ดังที่ได้เขียนไปใน
https://phyblas.hinaboshi.com/tsuchinoko10 รูปแบบการเขียนแบบนี้มีที่มาจากในภาษาซี และถูกใช้อย่างกว้างขวาง สามารถใช้ในภาษารูบีและ php ได้ด้วย
แต่ว่าในไพธอนรุ่น 3.6 เป็นต้นมามีอีกวิธีที่ถูกเพิ่มเข้ามา ซึ่งช่วยให้สะดวกในการเขียน และทำให้เขียนสั้นลงกว่าเดิม วิธีการนั้นเรียกว่า f-string
ในบทความนี้จะพูดถึงวิธีใช้ f-string
การใช้งานเบื้องต้น การใช้ f-string ทำได้โดยเติม f เปิดไว้ที่ด้านหน้าเครื่องหมายคำพูด แล้วใช้ {} ล้อมส่วนที่ต้องการแทรกค่าลงไป
khong = 'ผัก'
rakha = 100
print(f'ฉันไปตลาดซื้อ{khong} จ่ายไป {rakha} บาท')
ได้
ฉันไปตลาดซื้อผัก จ่ายไป 100 บาท
จะเห็นว่าการใช้นั้นง่ายดาย แค่แทรก {ชื่อตัวแปร} ลงไป
หากวิธีเดิมที่เขียนเป็น % ก็จะเป็นแบบนี้
print('ฉันไปตลาดซื้อ%s จ่ายไป %d บาท'%(khong,rakha))
หรือถ้าใช้การบวกต่อสายอักขระก็จะเป็นแบบนี้
print('ฉันไปตลาดซื้อ'+khong+' จ่ายไป '+str(rakha)+' บาท')
หากเทียบกันแล้ว f-string เขียนสั้นที่สุด
ขอแค่เติม f ไว้ข้างหน้า จะใช้กับเครื่องหมายคำพูดแบบซ้อนสามก็ได้
chue = 'โคอิซึมิ'
ayu = 15
ahan = 'ราเมง'
s = f'''ฉันชื่อ{chue}
อายุ {ayu} ปี
ชอบกิน{ahan}ที่สุด'''
print(s)
ได้
ฉันชื่อโคอิซึมิ
อายุ 15 ปี
ชอบกินราเมงที่สุด
ค่าที่ใส่ใน {} นั้นที่จริงแล้วไม่จำเป็นต้องเป็นตัวแปรเดี่ยวๆก็ได้ อาจใส่ค่าไปโดยตรง หรือใส่ฟังก์ชันคำนวณก็ยังได้
import math
print(f'180 องศาเท่ากับ {math.radians(180)} เรเดียน') # ได้ 180 องศาเท่ากับ 3.141592653589793 เรเดียน
print(f'{19} คูณ {18} เท่ากับ {19*18}') # ได้ 19 คูณ 18 เท่ากับ 342
print(f'อนันต์{math.inf}') # ได้ อนันต์inf
สิ่งที่อยู่ข้างใน {} จะมีการคำนวนหรือการทำงานของฟังก์ชันเหมือนกับเวลาที่อยู่ข้างนอก
แต่ว่าหากต้องการพิมพ์อักษร { หรือ } ในขณะที่ใช้ f-string ไปด้วยนั้น จะต้องเขียน {{ แทน { และเขียน }} แทน } ไม่เช่นนั้นจะเกิดข้อผิดพลาดได้
p = 'พลังคลื่นเต่า'
print(f'{p} {') # ได้ SyntaxError: f-string: expecting '}'
print(f'{p} {{') # ได้ พลังคลื่นเต่า {
print(f'{p} {{{{{{{{') # ได้ พลังคลื่นเต่า {{{{
การเพิ่มความยาวให้จำนวนช่องยาวตามที่กำหนด หากเติม : แล้วตามด้วยตัวเลขจะเป็นการกำหนดความยาวต่ำสุดของสายอักขระที่ต้องการ โดยมีการเติมช่องว่างมาเสริมให้ยาวเท่ากับที่กำหนด แต่ถ้าเลขที่ใส่ต่ำกว่าความยาวเดิมก็จะไม่มีการเปลี่ยนแปลง
ถ้าหากเป็นข้อมูลตัวเลขจะถูกจัดชิดขวา ถ้าเป็นชนิดสายอักขระจะถูกจัดชิดซ้าย
print(f'=={"สาย":10}==') # ได้ ==สาย ==
print(f'=={21121:10}==') # ได้ == 21121==
print(f'=={1.911:8}==') # ได้ == 1.911==
print(f'=={1.911:3}==') # ได้ ==1.911==
หากไม่ต้องการชิดตามนั้น สามารถกำหนดการจัดตำแหน่งในการเติมช่องว่างได้ตามที่ต้องการ โดยใส่ ^ หรือ < หรือ >
- < จัดชิดซ้าย
- ^ จัดไว้ตรงกลาง
- > จัดชิดขวา
เพียงแต่ว่าถ้าเป็นตัวเลขจะจัดชิดขวาอยู่แล้ว จึงไม่ต้องเติม > ก็ได้ ส่วนสายอักขระจะถูกจัดชิดซ้ายอยู่แล้ว จึงไม่ต้องเติม < ก็ได้ ผลก็ไม่ต่างกัน
ตัวอย่าง
print(f'm{112:<7}x') # ได้ m112 x
print(f'm{112:^7}x') # ได้ m 112 x
print(f'm{112:>7}x') # ได้ m 112x
print(f'm{1112:^7}x') # ได้ m 1112 x
หากใส่อักษรหรือเครื่องหมายอะไรไว้ทางซ้ายของ < ^ > ก็จะหมายถึงว่าให้เติมด้วยอักษรตัวนั้น แทนที่จะเป็นช่องว่างธรรมดา
print(f'~{"ปาด":#^9}~') # ได้ ~###ปาด###~
print(f'~{"ปวด":ฯ<9}~') # ได้ ~ปวดฯฯฯฯฯฯ~
print(f'~{"ปอด":)>9}~') # ได้ ~))))))ปอด~
การเติมเลข 0 ให้ตัวเลข สำหรับจำนวนตัวเลข หากต้องการเติมเลข 0 ไปทางขวาตามจำนวนที่กำหนดก็ทำได้โดยเขียน :0 ต่อด้วยจำนวนตัวอักษรรวมทั้งหมดขั้นต่ำที่ต้องการ สามารถใช้ <^> เพื่อกำหนดตำแหน่งของ 0 ที่จะเติมได้
print(f'${26:05}$') # ได้ $00026$
print(f'${26:^05}$') # ได้ $02600$
print(f'${26:<05}$') # ได้ $26000$
print(f'${2.6:<05}$') # ได้ $2.600$
ที่จริงแล้วหากใช้วิธีในหัวข้อที่แล้วโดยใส่เลข 0 ไปข้างหน้าก็ได้ผลแบบเดียวกัน
print(f'${27:0>5}$') # ได้ $00027$
print(f'${27:0^5}$') # ได้ $02700$
print(f'${27:0<5}$') # ได้ $27000$
เพียงแต่วิธีการเติม 0 หน้าตัวเลขจำนวนโดยตรงนี้ใช้กับสายอักขระไม่ได้ ถ้าใช้จะเกิดข้อผิดพลาด
print(f'${"หะ":05}$') # ได้ ValueError: '=' alignment not allowed in string format specifier
print(f'${"หะ":0>5}$') # ได้ $000หะ$
การใส่เครื่องหมายบวกให้ค่าบวก ปกติแล้วตัวเลขที่เป็นลบจะมีเครื่องหมาย - นำหน้า แต่ที่เป็น 0 หรือค่าบวกกลับไม่มีเครื่องหมาย + นำหน้า
เราสามารถกำหนดให้มีการเติมเครื่องหมายบวกนำหน้าเมื่อค่าเป็นบวกได้ โดยเติม :+ ต่อจากตัวเลข
พอทำแบบนี้ค่าบวกก็จะมีเครื่องหมาย + นำหน้า แต่ค่าที่เป็นลบก็จะไม่มีการเปลี่ยนแปลง
print(f'{10:+}') # ได้ +10
print(f'{-10:+}') # ได้ -10
หรือถ้าหากต้องการให้เป็นการเพิ่มช่องว่างแทนที่จะเป็นเครื่องหมายบวก ก็ทำได้โดยใส่ : แล้วตามด้วยช่องว่าง
print(f'a{10: }') # ได้ a 10
print(f'a{-10: }') # ได้ a-10
การทำแบบนี้มีประโยชน์ตรงที่ทำให้จำนวนอักษรของค่าบวกและลบเท่าเทียมกัน
หากต้องการทั้งเติม + ไปด้วยแล้วเติม 0 ไปด้วยก็ให้เติม + ก่อน แล้วค่อยเขียนส่วนกำหนดจำนวน 0 ต่อ
print(f'{17:+08}') # ได้ +0000017
การจัดการเลขทศนิยม หากเติม :f ต่อท้ายจำนวนตัวเลข จะเป็นการแสดงผลในรูปของจำนวนจริงที่มีทศนิยม ๖ ตำแหน่ง
print(f'{20:f}') # ได้ 20.000000
ถ้าอยากกำหนดเลขหลังจุดทศนิยมตามที่ต้องการให้ใส่ :.จำนวนทศนิยมf
print(f'{20:.2f}') # ได้ 20.00
print(f'{3.4567:.2f}') # ได้ 3.46
สามารถกำหนดการเติมเลข 0 ไปด้วยในเวลาเดียวกันโดยเติมตัวเลือกนี้แทรกระหว่าง : และ .
print(f'{3.4567:09.2f}') # ได้ 000003.46
สามารถใช้ F พิมพ์ใหญ่แทน f ได้ ผลก็เหมือนกัน แต่ข้อแตกต่างจะเกิดขึ้นเฉพาะเวลาที่เจอค่า inf หรือ nan จะถูกพิมพ์ด้วยพิมพ์ใหญ่แทนพิมพ์เล็ก
import math
print(f'{math.inf:09f}') # ได้ 000000inf
print(f'{math.inf:09F}') # ได้ 000000INF
print(f'{math.nan:09f}') # ได้ 000000nan
print(f'{math.nan:09F}') # ได้ 000000NAN
การแสดงผลเลขทศนิยมในรูปคูณ 10 ยกกำลัง ตัวเลขที่มีค่ามากหลายล้านหรือน้อยแค่หนึ่งส่วนล้านปกติแล้วก็อาจแสดงในรูปของ E จะง่ายกว่า เช่น 1100000 เป็น 1.1
วิธีการคล้ายกับการแสดงเลขทศนิยมธรรมดา แต่เปลี่ยจาก f เป็น e แต่ถ้าต้องการให้เป็น E พิมพ์ใหญ่ก็ใช้ E
print(f'{0.001234:.2e}') # ได้ 1.23e-03
print(f'{0.001234:011.2e}') # ได้ 0001.23e-03
print(f'{0.001234:011.2E}') # ได้ 0001.23E-03
ถ้าใช้ g หรือ G รูปแบบแสดงผลจะถูกกำหนดโดยอัตโนมัติว่าจะแสดงในรูปทศนิยมธรรมดาหรือในรูปคูณ 10 ยกกำลัง ขึ้นกับค่า
print(f'{1230000:g}') # ได้ 1.23e+06
print(f'{123000:g}') # ได้ 123000
print(f'{12.3:g}') # ได้12.3
print(f'{0.000123:g}') # ได้ 0.000123
print(f'{0.0000123:g}') # ได้ 1.23e-05
print(f'{0.00000123:G}') # ได้ 1.23E-06
การแสดงผลจำนวนเป็นร้อยละ ถ้าเขียนต่อจากตัวเลขด้วย :% ค่าที่ได้จะคูณ 100 แล้วมีคำว่า % ต่อท้าย
print(f'{0.99:%}') # ได้ 99.000000%
ปกติจะมาพร้อมกับเลขทศนิยม ๖ ตำแหน่ง แต่สามารถเติม . เพื่อระบุตำแหน่งเลขทศนิยมที่ต้องการได้เช่นเดียวกับ f หรือ e
print(f'{0.98:.3%}') # ได้ 98.000%
print(f'{0.97:09.2%}') # ได้ 00097.00%
เลขฐาน 2 ฐาน 8 ฐาน 16 ถ้าเติม :b จะเป็นการแปลงค่าเป็นเลขฐาน 2 ถ้าเติม :o จะแปลงเป็นฐาน 8 ถ้าเติม :x หรือ :X จะแปลงเป็นเลขฐาน 16
ข้อแตกต่างประหว่าว x กับ X ก็คือเวลาที่แทนตัวเลข 10 ถึง 15 ถ้าเป็น x จะใช้พิมพ์เล็ก a~f ถ้า X จะใช้พิมพ์ใหญ่ A~F
ตัวอย่าง
print(f'{11:@>10b}') # ได้ @@@@@@1011
print(f'{99:!>11o}') # ได้ !!!!!!!!143
print(f'{254:$<5x}') # ได้ fe$$$
print(f'{254:$^5X}') # ได้ $FE$$
หากเติม # ไปด้านหน้า b หรือ o หรือ x จะแสดง 0b หรือ 0o หรือ 0x เข้ามาด้านหน้า
print(f'{115:#b}') # ได้ 0b1110011
print(f'{777:#07o}') # ได้ 0o01411
print(f'{2241:#08x}') # ได้ 0x0008c1
print(f'~{2243:#8X}') # ได้ ~ 0X8C3
การใส่ , หรือ _ แทรกระหว่างตัวเลข เวลาเขียนตัวเลขยาวๆ บางครั้งเพื่อความเข้าใจง่ายบางคนก็ชอบใช้ , หรือ _ มากั้นทีละ ๓ ตัว
สามารถทำให้เป็นแบบนั้นได้โดยเติม :, หรือ :_
ตัวอย่าง
print(f'{1000000.0:,}') # ได้ 1,000,000.0
print(f'{123456789:_}') # ได้ 123_456_789.0
แต่ว่ารูปแบบนี้ใช้ได้แค่กับ , และ _ เท่านั้น หากจะใช้ตัวอื่นก็ต้องแทนที่เข้าไปเอง เช่นทำแบบนี้
print(f'{10000000000:,}'.replace(',','`')) # ได้ 10`000`000`000
ใช้กับ datetime f-string ยังสะดวกเวลาที่ใช้กับข้อมูลวันเวลา datetime ด้วย
รายละเอียดเรื่อง datetime อ่านได้ใน
https://phyblas.hinaboshi.com/20160621 ในออบเจ็กต์ datetime จะมีเมธอด strptime เอาไว้แสดงผลวันเวลาตามรูปแบบที่กำหนด
หากใช้ f-string สามารถเขียนรูปแบบการแสดงผล datetime ได้โดยตรงโดยไม่ต้องเรียกใช้ strptime เอง
ตัวอย่าง
wanwela = datetime.datetime(2019,7,14,1,25,19)
print(f'{wanwela:เวลา %H:%M:%S วันที่ %d เดือน %0m ปี %Y}') # ได้ เวลา 01:25:19 วันที่ 14 เดือน 07 ปี 2019
ความหมายของพวก %S %m %Y ฯลฯ มีเขียนไว้แล้วในบทความเรื่อง datetime
สรุปส่งท้าย จะเห็นว่าข้อดีของวิธีนี้คือมีความสามารถมากกว่าแบบเดิมที่ใช้ % และยังเขียนสั้นลงด้วย
เพียงแต่ว่าการทำงานโดยรวมอาจจะช้ากว่าเล็กน้อย รายละเอียดเรื่องนี้ได้เคยศึกษาเปรียบเทียบแล้วเขียนไว้ใน
https://phyblas.hinaboshi.com/20190713 อีกทั้งเนื่องจากเพิ่งใช้ได้ตั้งแต่เวอร์ชัน 3.6 ทำให้หากต้องการเขียนโปรแกรมที่รองรับรุ่นเก่าได้ก็จะยังไม่ควรใช้ f-string อยู่ดี ดังนั้นกว่า f-string จะเป็นที่ใช้กันแพร่หลายทั่วไปได้คงต้องใช้เวลา