φυβλαςのβλογ
บล็อกของ phyblas



เปรียบเทียบระหว่างการใช้ %, ใช้ format และใช้ f-string ใน python
เขียนเมื่อ 2019/07/13 07:45
ในไพธอนเวลาที่จะสร้างหรือเรียบเรียงสายอักขระนั้นมี ๓ วิธีที่ใช้ได้คือ
- '%s%s'%(a,b) เป็นวิธีดั้งเดิม ใช้รูปแบบเหมือน printf ของภาษาซี มีใช้ในหลายภาษา
- '{}{}'.format(a,b) เป็นรูปแบบเฉพาะของภาษาไพธอน แย่การเขียนค่อนข้างเยิ่นเย้อ
- f'{a}{b}' วิธีนี้มีชื่อเรียกเฉพาะว่า f-string เป็นวิธีใหม่ที่เพิ่มเข้ามาในไพธอน 3.6 ไม่สามารถใช้ในไพธอนรุ่นเก่าได้

ทั้ง ๓ วิธีนั้นก็มีข้อดีข้อเสียต่างกันไป จะเลือกวิธีไหนก็อาจแล้วแต่คนถนัด

ในที่นี้จะขอพิจารณาเทียบในเรื่องของความเร็วดูว่าถ้าใช้ ๓ วิธีนี้ทำสิ่งเดียวกัน อย่างไหนจะดีกว่าในแง่ประสิทธิภาพ

ผลการเปรียบเทียบจะต่างกันออกไปขึ้นอยู่กับชนิดข้อมูลที่ใช้แปลง ในที่นี่ลองสอดสอบกรณีดังนี้
- เอาสายอักขระมาต่อเฉยๆ (%s, {})
- เอา int มาแปลงเป็นสายอักขระ (%d, {})
- เอา int เต็มมาแปลงเป็นสายอักขระโดยมีการเติม 0 ตามจำนวนที่กำหนด (%010d, {:010})
- เอา float มาแปลงเป็นสายอักขระโดยเขียนแบบเอ็กซ์โพเนนเชียลโดยไม่กำหนดความยาวเลขทศนิยม (%e, {:e})
- เอา float มาแปลงเป็นสายอักขระโดยเขียนแบบเอ็กซ์โพเนนเชียลโดยกำหนดความยาวเลขทศนิยม (%.10e, {:.e})
- เอา float มาแปลงเป็นสายอักขระโดยไม่กำหนดความยาวเลขทศนิยม (%f, {:f})
- เอา float มาแปลงเป็นสายอักขระโดยกำหนดความยาวเลขทศนิยม (%.10f, {:.f})
- เอา float มาแปลงเป็นสายอักขระโดยไม่ระบุชัด (%s, {})
- เอา None มาแปลงเป็นสายอักขระ
- เอา list แปลงเป็นสายอักขระ

โค้ดสำหรับทดสอบเขียนดังนี้

import time
import numpy as np
import matplotlib.pyplot as plt

tt =[]
n = 100000



t = [[],[],[]]
for j in range(5):
    a = 'กข'
    b = 'คง'
    
    t0 = time.time()
    for i in range(n):
        '%s%s'%(a, b)
    t[0].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        '{}{}'.format(a, b)
    t[1].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        f'{a}{b}'
    t[2].append(time.time()-t0)

tt.append(t)



t = [[],[],[]]
for j in range(5):
    a = 10
    b = 200
    
    t0 = time.time()
    for i in range(n):
        '%d%d'%(a, b)
    t[0].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        '{}{}'.format(a, b)
    t[1].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        f'{a}{b}'
    t[2].append(time.time()-t0)

tt.append(t)



t = [[],[],[]]
for j in range(5):
    a = 10
    b = 200
    
    t0 = time.time()
    for i in range(n):
        '%010d%010d'%(a, b)
    t[0].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        '{:010}{:010}'.format(a, b)
    t[1].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        f'{a:010}{b:010}'
    t[2].append(time.time()-t0)

tt.append(t)



t = [[],[],[]]
for j in range(5):
    a = 1.522555
    b = 3.125
    
    t0 = time.time()
    for i in range(n):
        '%e%e'%(a, b)
    t[0].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        '{:e}{:e}'.format(a, b)
    t[1].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        f'{a:e}{b:e}'
    t[2].append(time.time()-t0)

tt.append(t)



t = [[],[],[]]
for j in range(5):
    a = 1.522555
    b = 3.125
    
    t0 = time.time()
    for i in range(n):
        '%.10e%.10e'%(a, b)
    t[0].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        '{:.10e}{:.10e}'.format(a, b)
    t[1].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        f'{a:.10e}{b:.10e}'
    t[2].append(time.time()-t0)

tt.append(t)



t = [[],[],[]]
for j in range(5):
    a = 1.522555
    b = 3.125
    
    t0 = time.time()
    for i in range(n):
        '%f%f'%(a, b)
    t[0].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        '{:f}{:f}'.format(a, b)
    t[1].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        f'{a:f}{b:f}'
    t[2].append(time.time()-t0)

tt.append(t)



t = [[],[],[]]
for j in range(5):
    a = 1.522555
    b = 3.125
    
    t0 = time.time()
    for i in range(n):
        '%.10f%.10f'%(a, b)
    t[0].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        '{:.10f}{:.10f}'.format(a, b)
    t[1].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        f'{a:.10f}{b:.10f}'
    t[2].append(time.time()-t0)

tt.append(t)



t = [[],[],[]]
for j in range(5):
    a = 1.522555
    b = 3.125
    
    t0 = time.time()
    for i in range(n):
        '%s%s'%(a, b)
    t[0].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        '{}{}'.format(a, b)
    t[1].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        f'{a}{b}'
    t[2].append(time.time()-t0)

tt.append(t)



t = [[],[],[]]
for j in range(5):
    a = None
    b = None
    
    t0 = time.time()
    for i in range(n):
        '%s%s'%(a, b)
    t[0].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        '{}{}'.format(a, b)
    t[1].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        f'{a}{b}'
    t[2].append(time.time()-t0)

tt.append(t)



t = [[],[],[]]
for j in range(5):
    a = list(range(1,6))
    b = list(range(11,16))
    
    t0 = time.time()
    for i in range(n):
        '%s%s'%(a, b)
    t[0].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        '{}{}'.format(a, b)
    t[1].append(time.time()-t0)
    
    t0 = time.time()
    for i in range(n):
        f'{a}{b}'
    t[2].append(time.time()-t0)

tt.append(t)



tt = np.array(tt)/n*1e6
plt.figure(figsize=[6.5,6])

plt.subplot(211)
for i,c in enumerate(['#ffaaaa','#aaffaa','#aaaaff']):
    plt.bar(np.arange(10)+(i-1)/4.,tt[:,i].mean(1),width=0.25,yerr=tt[:,i].std(1),capsize=4,color=c,ecolor='#332255')

plt.legend(['ใช้ %','ใช้ format','ใช้ f-string'],prop={'family':'Tahoma'})
plt.ylabel('เวลา (ไมโครวินาที)',family='Tahoma')
plt.xticks([])

plt.subplot(212)
for i,c in enumerate(['#ffaaaa','#aaffaa','#aaaaff']):
    plt.bar(np.arange(10)+(i-1)/4.,(tt[:,i]/tt[:,0]).mean(1),width=0.25,yerr=(tt[:,i]/tt[:,0]).std(1),capsize=5,color=c,ecolor='#332211')

plt.ylabel('จำนวนเท่าของแบบใช้ %',family='Tahoma')
plt.xticks(np.arange(10),['s','d','010d','e','.10e','f','.10f','f>>s','None','list'])

plt.tight_layout()
plt.show()


ผลที่ได้



สรุปได้ว่าโดยรวมแล้ววิธีการดั้งเดิมอย่างการใช้ % นั้นเร็วที่สุด ส่วน .format นั้นยังไงก็ช้ากว่ากว่า % ทุกกรณี

ส่วน f-string นั้นจะเร็วมากในกรณีที่ป้อนสายอักขระโดยตรง แต่พอแปลง int กลับจะเร็วพอๆกันกับการใช้ %

แต่เมื่อมีการกำหนดให้เติมเลข 0 แบบนี้ f-string จะทำงานช้าลงมาก ช้ายิ่งกว่า .format เสียอีก

สำหรับการแปลง float นั้น f-string ช้าสุดในทุกกรณี

ดังนั้นหากคำนึงถึงความเร็ว การใช้ % ยังเร็วที่สุด

แต่ f-string อาจเหมาะเวลาที่ต้องการป้อนข้อมูลที่เดิมทีเป็นสายอักขระ เพราะเขียนได้กระชับสั้นที่สุดและยังเร็วที่สุด

อีกทั้ง อันนี้แค่เทียบในแง่ความเร็วเป็นหลัก แต่หากพูดถึงความสามารถ f-string สามารถทำอะไรบางอย่างที่ไม่สามารถใช้ % ทำได้ เช่น แทรกจุลภาคลงใประหว่างตัวเลข
a = 123456789
print(f'{a:,}') # ได้ 123,456,789

ยังไงก็อาจแยกใช้ตามความเหมาะสม ขึ้นอยู่กับว่าต้องการใช้ทำอะไร


-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
python
-- numpy
-- matplotlib

-- pandas
-- pytorch
maya
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
javascript
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
เรียนภาษาจีน
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  ค้นหาบทความ

  บทความแนะนำ

เรียนรู้วิธีการใช้ regular expression (regex)
หลักการเขียนทับศัพท์ภาษาจีนกวางตุ้ง
การใช้ unix shell เบื้องต้น ใน linux และ mac
หลักการเขียนทับศัพท์ภาษาจีนกลาง
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
บันทึกการเที่ยวสวีเดน 1-12 พ.ค. 2014
แนะนำองค์การวิจัยและพัฒนาการสำรวจอวกาศญี่ปุ่น (JAXA)
เล่าประสบการณ์ค่ายอบรมวิชาการทางดาราศาสตร์โดยโซวเคนได 10 - 16 พ.ย. 2013
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
บันทึกการเที่ยวญี่ปุ่นครั้งแรกในชีวิต - ทุกอย่างเริ่มต้นที่สนามบินนานาชาติคันไซ
หลักการเขียนทับศัพท์ภาษาญี่ปุ่น
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ
ทำไมถึงอยากมาเรียนต่อนอก
เหตุผลอะไรที่ต้องใช้ภาษาวิบัติ?

ไทย

日本語

中文