Home / Example - Don't Repeat Yourself (DRY)

Example - Don't Repeat Yourself (DRY)

You are not logged in.

If you are a current student, please Log In for full access to this page.

Table of Contents

1) ตัวอย่างโค้ดที่พบได้บ่อยในสถานการณ์จริง

ข้อมูลจาก https://data.go.th/dataset/ulg-station

ดาวน์โหลดมาลองได้ด้วยคำสั่ง

!wget https://data.go.th/dataset/d8a056fe-3ded-4620-944e-10f87c4f143a/resource/9c33fabf-d564-4bde-bc7c-14195c5c578d/download/02-ulg-21-01jan-sta.csv
!wget https://data.go.th/dataset/d8a056fe-3ded-4620-944e-10f87c4f143a/resource/768ed19a-31af-4c6f-918b-366daed07e41/download/02-ulg-21-11nov-sta.csv
import pandas as pd
พย = pd.read_csv("02-ulg-21-11nov-sta.csv", encoding="ISO-8859-11")
พย.columns = พย.loc[3]
พย = พย.loc[5:94]
พย = พย.dropna(subset=["ลำดับที่"])
พย = พย.reset_index()
del พย["index"]
พย.columns.name = None
พย = พย.rename(columns={"รวมทั้งสิ้น" : "รวมทั้งสิ้น(พันลิตร)"})
พย['ปตท.'] = พย['ปตท.'].str.replace(",","").astype(float)
พย['เชลล์'] = พย['เชลล์'].str.replace(",","").astype(float)
พย['เชฟรอน(ไทย)'] = พย['เชฟรอน(ไทย)'].str.replace(",","").astype(float)
พย['ซัสโก้'] = พย['ซัสโก้'].str.replace(",","").astype(float)
พย['พีทีจี'] = พย['พีทีจี'].str.replace(",","").astype(float)
พย['ไทยออยล์'] = พย['ไทยออยล์'].str.replace(",","").astype(float)
พย['ซัสโก้ ดีลเลอร์ส'] = พย['ซัสโก้ ดีลเลอร์ส'].str.replace(",","").astype(float)
พย['สยามเฆมี'] = พย['สยามเฆมี'].str.replace(",","").astype(float)
พย['ปตท. บริหารธุรกิจค้าปลีก'] = พย['ปตท. บริหารธุรกิจค้าปลีก'].str.replace(",","").astype(float)
พย['ปตท. น้ำมันและการค้าปลีก'] = พย['ปตท. น้ำมันและการค้าปลีก'].str.replace(",","").astype(float)
พย["รวมทั้งสิ้น(พันลิตร)"] = พย["รวมทั้งสิ้น(พันลิตร)"].str.replace(",","").astype("float")
พย.head()
ลำดับที่ จังหวัด ปตท. เชลล์ เชฟรอน(ไทย) ซัสโก้ พีทีจี ไทยออยล์ ซัสโก้ ดีลเลอร์ส สยามเฆมี ปตท. บริหารธุรกิจค้าปลีก ปตท. น้ำมันและการค้าปลีก รวมทั้งสิ้น(พันลิตร)
0 1 กรุงเทพมหานคร 3.0 NaN 709.0 560.0 13.0 150.0 145.0 34.0 131.0 1173.0 2919.0
1 2 สมุทรปราการ NaN NaN 69.0 36.0 NaN 21.0 29.0 NaN NaN 138.0 294.0
2 3 นนทบุรี NaN NaN 147.0 36.0 NaN 67.0 66.0 NaN 18.0 246.0 580.0
3 4 ปทุมธานี NaN NaN 51.0 39.0 NaN 39.0 NaN NaN 6.0 111.0 247.0
4 5 พระนครศรีอยุธยา NaN NaN 27.0 NaN NaN 12.0 NaN NaN 42.0 93.0 174.0
มค = pd.read_csv("02-ulg-21-01jan-sta.csv", encoding="ISO-8859-11")
มค.columns = มค.loc[3]
มค = มค.loc[5:94]
มค = มค.dropna(subset=["ลำดับที่"])
มค = มค.reset_index()
del มค["index"]
มค.columns.name = None
มค = มค.rename(columns={"รวมทั้งสิ้น" : "รวมทั้งสิ้น(พันลิตร)"})
มค['ปตท.'] = มค['ปตท.'].str.replace(",","").astype(float)
มค['เชลล์'] = มค['เชลล์'].str.replace(",","").astype(float)
มค['เชฟรอน(ไทย)'] = มค['เชฟรอน(ไทย)'].str.replace(",","").astype(float)
มค['ซัสโก้'] = มค['ซัสโก้'].str.replace(",","").astype(float)
มค['พีทีจี'] = มค['พีทีจี'].str.replace(",","").astype(float)
มค['ไทยออยล์'] = มค['ไทยออยล์'].str.replace(",","").astype(float)
มค['ซัสโก้ ดีลเลอร์ส'] = มค['ซัสโก้ ดีลเลอร์ส'].str.replace(",","").astype(float)
มค['สยามเฆมี'] = มค['สยามเฆมี'].str.replace(",","").astype(float)
มค['ปตท. บริหารธุรกิจค้าปลีก'] = มค['ปตท. บริหารธุรกิจค้าปลีก'].str.replace(",","").astype(float)
มค['ปตท. น้ำมันและการค้าปลีก'] = มค['ปตท. น้ำมันและการค้าปลีก'].str.replace(",","").astype(float)
มค["รวมทั้งสิ้น(พันลิตร)"] = มค["รวมทั้งสิ้น(พันลิตร)"].str.replace(",","").astype("float")
มค.head()
ลำดับที่ จังหวัด ปตท. เชลล์ เชฟรอน(ไทย) ซัสโก้ พีทีจี ไทยออยล์ ซัสโก้ ดีลเลอร์ส สยามเฆมี ปตท. บริหารธุรกิจค้าปลีก ปตท. น้ำมันและการค้าปลีก รวมทั้งสิ้น(พันลิตร)
0 1 กรุงเทพมหานคร 28.0 NaN 845.0 610.0 9.0 169.0 179.0 23.0 136.0 1300.0 3299.0
1 2 สมุทรปราการ NaN NaN 83.0 52.0 NaN 26.0 36.0 NaN NaN 140.0 337.0
2 3 นนทบุรี NaN NaN 209.0 42.0 NaN 84.0 79.0 NaN 29.0 258.0 701.0
3 4 ปทุมธานี NaN NaN 66.0 53.0 NaN 54.0 NaN NaN 6.0 99.0 279.0
4 5 พระนครศรีอยุธยา NaN NaN 40.0 NaN NaN 6.0 NaN NaN 25.0 118.0 189.0

2) Don't Repeat Yourself (DRY)

ในการพัฒนาซอฟท์แวร์ หรือการเขียนโปรแกรมจะมีหลักการ Don't Repeat Yourself (https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) ซึ่งใจความหลักคือทุกครั้งที่เราทำซ้ำ (copy-paste โค้ดตัวเอง) เราสามารถพัฒนาวิธีการเขียนโปรแกรมนั้นได้

2.1) การใช้ loop ในการ DRY

จากโค้ดเดิม

พย.columns = พย.loc[3]
พย = พย.loc[5:94]
พย = พย.dropna(subset=["ลำดับที่"])
พย = พย.reset_index()
del พย["index"]
พย.columns.name = None
พย = พย.rename(columns={"รวมทั้งสิ้น" : "รวมทั้งสิ้น(พันลิตร)"})
พย['ปตท.'] = พย['ปตท.'].str.replace(",","").astype(float)
พย['เชลล์'] = พย['เชลล์'].str.replace(",","").astype(float)
พย['เชฟรอน(ไทย)'] = พย['เชฟรอน(ไทย)'].str.replace(",","").astype(float)
พย['ซัสโก้'] = พย['ซัสโก้'].str.replace(",","").astype(float)
พย['พีทีจี'] = พย['พีทีจี'].str.replace(",","").astype(float)
พย['ไทยออยล์'] = พย['ไทยออยล์'].str.replace(",","").astype(float)
พย['ซัสโก้ ดีลเลอร์ส'] = พย['ซัสโก้ ดีลเลอร์ส'].str.replace(",","").astype(float)
พย['สยามเฆมี'] = พย['สยามเฆมี'].str.replace(",","").astype(float)
พย['ปตท. บริหารธุรกิจค้าปลีก'] = พย['ปตท. บริหารธุรกิจค้าปลีก'].str.replace(",","").astype(float)
พย['ปตท. น้ำมันและการค้าปลีก'] = พย['ปตท. น้ำมันและการค้าปลีก'].str.replace(",","").astype(float)
พย["รวมทั้งสิ้น(พันลิตร)"] = พย["รวมทั้งสิ้น(พันลิตร)"].str.replace(",","").astype("float")
พย.head()

จะเห็นว่าส่วนที่ซ้ำกันมากที่สุดคือ

พย['ปตท.'] = พย['ปตท.'].str.replace(",","").astype(float)
พย['เชลล์'] = พย['เชลล์'].str.replace(",","").astype(float)
พย['เชฟรอน(ไทย)'] = พย['เชฟรอน(ไทย)'].str.replace(",","").astype(float)
พย['ซัสโก้'] = พย['ซัสโก้'].str.replace(",","").astype(float)
พย['พีทีจี'] = พย['พีทีจี'].str.replace(",","").astype(float)
พย['ไทยออยล์'] = พย['ไทยออยล์'].str.replace(",","").astype(float)
พย['ซัสโก้ ดีลเลอร์ส'] = พย['ซัสโก้ ดีลเลอร์ส'].str.replace(",","").astype(float)
พย['สยามเฆมี'] = พย['สยามเฆมี'].str.replace(",","").astype(float)
พย['ปตท. บริหารธุรกิจค้าปลีก'] = พย['ปตท. บริหารธุรกิจค้าปลีก'].str.replace(",","").astype(float)
พย['ปตท. น้ำมันและการค้าปลีก'] = พย['ปตท. น้ำมันและการค้าปลีก'].str.replace(",","").astype(float)
พย["รวมทั้งสิ้น(พันลิตร)"] = พย["รวมทั้งสิ้น(พันลิตร)"].str.replace(",","").astype("float")

ซึ่งในการเขียนโปรแกรมเรามีโครงสร้างสำหรับการทำซ้ำอยู่แล้ว (loop) จึงสามารถนำมาใช้ได้ เช่น

df = pd.read_csv("02-ulg-21-11nov-sta.csv", encoding="ISO-8859-11")
df.columns = df.loc[3]
df = df.loc[5:94]
df = df.dropna(subset=["ลำดับที่"])
df = df.reset_index()
del df["index"]
df.columns.name = None
df = df.rename(columns={"รวมทั้งสิ้น" : "รวมทั้งสิ้น(พันลิตร)"})
for col in ['ปตท.', 'เชลล์', 'เชฟรอน(ไทย)', 'ซัสโก้',
       'พีทีจี', 'ไทยออยล์', 'ซัสโก้ ดีลเลอร์ส', 'สยามเฆมี',
       'ปตท. บริหารธุรกิจค้าปลีก', 'ปตท. น้ำมันและการค้าปลีก',
       'รวมทั้งสิ้น(พันลิตร)']:
    df[col] = df[col].str.replace(",", "").astype(float)
df
ลำดับที่ จังหวัด ปตท. เชลล์ เชฟรอน(ไทย) ซัสโก้ พีทีจี ไทยออยล์ ซัสโก้ ดีลเลอร์ส สยามเฆมี ปตท. บริหารธุรกิจค้าปลีก ปตท. น้ำมันและการค้าปลีก รวมทั้งสิ้น(พันลิตร)
0 1 กรุงเทพมหานคร 3.0 NaN 709.0 560.0 13.0 150.0 145.0 34.0 131.0 1173.0 2919.0
1 2 สมุทรปราการ NaN NaN 69.0 36.0 NaN 21.0 29.0 NaN NaN 138.0 294.0
2 3 นนทบุรี NaN NaN 147.0 36.0 NaN 67.0 66.0 NaN 18.0 246.0 580.0
3 4 ปทุมธานี NaN NaN 51.0 39.0 NaN 39.0 NaN NaN 6.0 111.0 247.0
4 5 พระนครศรีอยุธยา NaN NaN 27.0 NaN NaN 12.0 NaN NaN 42.0 93.0 174.0
... ... ... ... ... ... ... ... ... ... ... ... ... ...
72 73 ตรัง NaN NaN 20.0 75.0 NaN NaN NaN NaN NaN 28.0 123.0
73 74 พัทลุง NaN NaN 9.0 NaN 6.0 NaN NaN NaN NaN 3.0 18.0
74 75 ปัตตานี NaN NaN NaN NaN NaN NaN NaN NaN NaN 4.0 4.0
75 76 ยะลา NaN NaN NaN NaN 37.0 NaN NaN NaN NaN 42.0 79.0
76 77 นราธิวาส NaN NaN 6.0 NaN NaN NaN NaN NaN NaN NaN 6.0

77 rows × 13 columns

ทั้งนี้ ค่า list ['ปตท.', 'เชลล์', 'เชฟรอน(ไทย)', 'ซัสโก้', 'พีทีจี', 'ไทยออยล์', 'ซัสโก้ ดีลเลอร์ส', 'สยามเฆมี', 'ปตท. บริหารธุรกิจค้าปลีก', 'ปตท. น้ำมันและการค้าปลีก', 'รวมทั้งสิ้น(พันลิตร)'] ที่เรานำมาวนลูปนั้นเป็นชื่อคอลัมน์ เพราะฉะนั้นเราสามารถดึงค่าพวกนี้มาจาก df.columns ได้เช่นกัน

df.columns
Index(['ลำดับที่', 'จังหวัด', 'ปตท.', 'เชลล์', 'เชฟรอน(ไทย)', 'ซัสโก้',
       'พีทีจี', 'ไทยออยล์', 'ซัสโก้ ดีลเลอร์ส', 'สยามเฆมี',
       'ปตท. บริหารธุรกิจค้าปลีก', 'ปตท. น้ำมันและการค้าปลีก',
       'รวมทั้งสิ้น(พันลิตร)'],
      dtype='object')
df.columns[3:]
Index(['เชลล์', 'เชฟรอน(ไทย)', 'ซัสโก้', 'พีทีจี', 'ไทยออยล์',
       'ซัสโก้ ดีลเลอร์ส', 'สยามเฆมี', 'ปตท. บริหารธุรกิจค้าปลีก',
       'ปตท. น้ำมันและการค้าปลีก', 'รวมทั้งสิ้น(พันลิตร)'],
      dtype='object')

เก็บค่าที่ต้องการไว้ในตัวแปร

columns_to_convert = df.columns[3:]

นำมารวมกับของเดิม จะได้เป็น

df = pd.read_csv("02-ulg-21-11nov-sta.csv", encoding="ISO-8859-11")
df.columns = df.loc[3]
df = df.loc[5:94]
df = df.dropna(subset=["ลำดับที่"])
df = df.reset_index()
del df["index"]
df.columns.name = None
df = df.rename(columns={"รวมทั้งสิ้น" : "รวมทั้งสิ้น(พันลิตร)"})
columns_to_convert = df.columns[3:]
for col in columns_to_convert:
    df[col] = df[col].str.replace(",", "").astype(float)
df
ลำดับที่ จังหวัด ปตท. เชลล์ เชฟรอน(ไทย) ซัสโก้ พีทีจี ไทยออยล์ ซัสโก้ ดีลเลอร์ส สยามเฆมี ปตท. บริหารธุรกิจค้าปลีก ปตท. น้ำมันและการค้าปลีก รวมทั้งสิ้น(พันลิตร)
0 1 กรุงเทพมหานคร 3 NaN 709.0 560.0 13.0 150.0 145.0 34.0 131.0 1173.0 2919.0
1 2 สมุทรปราการ NaN NaN 69.0 36.0 NaN 21.0 29.0 NaN NaN 138.0 294.0
2 3 นนทบุรี NaN NaN 147.0 36.0 NaN 67.0 66.0 NaN 18.0 246.0 580.0
3 4 ปทุมธานี NaN NaN 51.0 39.0 NaN 39.0 NaN NaN 6.0 111.0 247.0
4 5 พระนครศรีอยุธยา NaN NaN 27.0 NaN NaN 12.0 NaN NaN 42.0 93.0 174.0
... ... ... ... ... ... ... ... ... ... ... ... ... ...
72 73 ตรัง NaN NaN 20.0 75.0 NaN NaN NaN NaN NaN 28.0 123.0
73 74 พัทลุง NaN NaN 9.0 NaN 6.0 NaN NaN NaN NaN 3.0 18.0
74 75 ปัตตานี NaN NaN NaN NaN NaN NaN NaN NaN NaN 4.0 4.0
75 76 ยะลา NaN NaN NaN NaN 37.0 NaN NaN NaN NaN 42.0 79.0
76 77 นราธิวาส NaN NaN 6.0 NaN NaN NaN NaN NaN NaN NaN 6.0

77 rows × 13 columns

จะ clean ข้อมูลของหนึ่งเดือนได้กระชับมากขึ้น

2.2) การใช้ Function ช่วยในการ DRY

และจากเดิมที่ต้องทำซ้ำกับหลาย ๆ เดือน ในส่วนนี้เราสามารถนำ concept function มาใช้ได้

โดยสังเกตว่าในแต่ละเดือนเราใช้คำสั่งเหมือนกันทั้งหมด แตกต่างกันเพียงแค่ชื่อไฟล์เท่านั้น เพราะฉะนั้นสามารถทำเป็น function ที่รับชื่อไฟล์ (filename) เป็น parameter ได้ดังนี้

def clean_one_month(filename):
    df = pd.read_csv(filename, encoding="ISO-8859-11")
    df.columns = df.loc[3]
    df = df.loc[5:94]
    df = df.dropna(subset=["ลำดับที่"])
    df = df.reset_index()
    del df["index"]
    df.columns.name = None
    df = df.rename(columns={"รวมทั้งสิ้น" : "รวมทั้งสิ้น(พันลิตร)"})
    columns_to_convert = df.columns[3:]
    for col in columns_to_convert:
        df[col] = df[col].str.replace(",", "").astype(float)
    return df
df = clean_one_month("02-ulg-21-11nov-sta.csv")
df
ลำดับที่ จังหวัด ปตท. เชลล์ เชฟรอน(ไทย) ซัสโก้ พีทีจี ไทยออยล์ ซัสโก้ ดีลเลอร์ส สยามเฆมี ปตท. บริหารธุรกิจค้าปลีก ปตท. น้ำมันและการค้าปลีก รวมทั้งสิ้น(พันลิตร)
0 1 กรุงเทพมหานคร 3 NaN 709.0 560.0 13.0 150.0 145.0 34.0 131.0 1173.0 2919.0
1 2 สมุทรปราการ NaN NaN 69.0 36.0 NaN 21.0 29.0 NaN NaN 138.0 294.0
2 3 นนทบุรี NaN NaN 147.0 36.0 NaN 67.0 66.0 NaN 18.0 246.0 580.0
3 4 ปทุมธานี NaN NaN 51.0 39.0 NaN 39.0 NaN NaN 6.0 111.0 247.0
4 5 พระนครศรีอยุธยา NaN NaN 27.0 NaN NaN 12.0 NaN NaN 42.0 93.0 174.0
... ... ... ... ... ... ... ... ... ... ... ... ... ...
72 73 ตรัง NaN NaN 20.0 75.0 NaN NaN NaN NaN NaN 28.0 123.0
73 74 พัทลุง NaN NaN 9.0 NaN 6.0 NaN NaN NaN NaN 3.0 18.0
74 75 ปัตตานี NaN NaN NaN NaN NaN NaN NaN NaN NaN 4.0 4.0
75 76 ยะลา NaN NaN NaN NaN 37.0 NaN NaN NaN NaN 42.0 79.0
76 77 นราธิวาส NaN NaN 6.0 NaN NaN NaN NaN NaN NaN NaN 6.0

77 rows × 13 columns

df = clean_one_month("02-ulg-21-01jan-sta.csv")
df
ลำดับที่ จังหวัด ปตท. เชลล์ เชฟรอน(ไทย) ซัสโก้ พีทีจี ไทยออยล์ ซัสโก้ ดีลเลอร์ส สยามเฆมี ปตท. บริหารธุรกิจค้าปลีก ปตท. น้ำมันและการค้าปลีก รวมทั้งสิ้น(พันลิตร)
0 1 กรุงเทพมหานคร 28 NaN 845.0 610.0 9.0 169.0 179.0 23.0 136.0 1300.0 3299.0
1 2 สมุทรปราการ NaN NaN 83.0 52.0 NaN 26.0 36.0 NaN NaN 140.0 337.0
2 3 นนทบุรี NaN NaN 209.0 42.0 NaN 84.0 79.0 NaN 29.0 258.0 701.0
3 4 ปทุมธานี NaN NaN 66.0 53.0 NaN 54.0 NaN NaN 6.0 99.0 279.0
4 5 พระนครศรีอยุธยา NaN NaN 40.0 NaN NaN 6.0 NaN NaN 25.0 118.0 189.0
... ... ... ... ... ... ... ... ... ... ... ... ... ...
72 73 ตรัง NaN NaN 25.0 74.0 NaN NaN NaN NaN NaN 61.0 160.0
73 74 พัทลุง NaN NaN 9.0 NaN 3.0 NaN NaN NaN NaN 6.0 18.0
74 75 ปัตตานี NaN NaN NaN NaN NaN NaN NaN NaN NaN 4.0 4.0
75 76 ยะลา NaN NaN NaN NaN 15.0 NaN NaN NaN NaN 50.0 65.0
76 77 นราธิวาส NaN NaN 12.0 NaN NaN NaN NaN NaN NaN NaN 12.0

77 rows × 13 columns

3) สรุป

ทั้งนี้การ DRY ก็ใช้เวลาในการเขียนมากขึ้นเช่นกัน จึงนำไปปรับใช้ได้ตามความถนัดและความเหมาะสมในสถานการณ์ต่าง ๆ กัน