Tutorial

pipe Python Package ที่ทำให้ Code น่ารักขึ้นเยอะ

By Arnon Puitrakul - 05 พฤศจิกายน 2021

pipe Python Package ที่ทำให้ Code น่ารักขึ้นเยอะ

เมื่อไม่กี่วันก่อนระหว่างเปิดหาอะไรในเน็ตไปเรื่อยก็ไปเจอกับของเล่นใหม่เข้าโดยบังเอิญ แล้วพอเอามาลองใช้จริง ๆ เออ มันก็แปลก ๆ ดีนะ เวลาเขียนแล้วมัน งง ๆ ว่าเอ๊ะอิหยังวะอยู่พอสมควรเลย นั่นคือ Package ที่ชื่อว่า pipe ใช่แล้ว มันคือ pipe เดียวกับที่เราใช้ใน Command Line สำหรับเอาผลของ Expression ก่อนหน้าไปใส่เป็น Input ของตัวต่อไปนั่นเองเหมือนกันเลย โดยที่ใน Package นี้ตัวอย่างที่เราว่าใช้งานได้โหด ๆ เลยคือการทำงานกับพวก List ทั้งหลาย ยิ่งถ้าข้อมูลเราเยอะ ๆ ต้องทำ Operation หลาย ๆ ตัวเราว่าโคตรเหมาะเลย ทำให้ง่ายกว่าเดิมเยอะมาก

ติดตั้ง pipe

pip install pipe

การติดตั้ง pipe ทำได้ไม่ยากเลย เราสามารถใช้ pip ได้เลย สำหรับคนที่ใช้ conda เราลองแล้วมันหา Package ไม่เจอ เราก็ทำการ Install ผ่าน pip ได้เช่นกันจากคำสั่งด้านบน

from pipe import where

เพื่อเป็นการเช็คว่าเราติดตั้งผ่านแล้วจริง ๆ เราอาจจะลอง Import มันเข้ามาก็ได้ ถ้าไม่มีปัญหาอะไรก็คือ การติดตั้งเรียบร้อยดีไม่มีปัญหา

Your First Pipe

from random import randint
from pipe import where

people_age = [randint(x, x+20) for x in range(80)]
adult_people = people_age | where (lambda x : x>18)

หลังจากเราติดตั้งแล้ว เราลองมาใช้งาน Pipe กันดีกว่า เราเริ่มจากคำสั่งที่ง่าย ๆ ก่อนละกันเป็นการเลือกข้อมูล โดยที่เราสามารถกำหนดเงื่อนไขได้ เหมือนกับเราเลือกข้อมูลใน SQL เลยอะไรแบบนั้น ในตัวอย่างด้านบน เราทำการสร้าง List ปลอม ๆ ขึ้นมาเหมือนกับเป็นอายุของคนละกัน จำนวน 80 คนด้วยกัน จากนั้น เราต้องการที่จะ Filter เพื่อเอาคนที่อายุ มากกว่า 18 ออกมา เราเลย Pipe แล้วให้มันวิ่งไปที่ where ในนั้น สิ่งที่เราใส่ลงไปก็จะเป็น Function สำหรับการเลือก ซึ่งในที่นี้คือ เราต้องการ Item ที่มากกว่า 18 โดยการใช้ Anonymous Function

adult_people = []
for person_age in people_age :
    if person_age > 18 :
        adult_people.append(person_age)

ถ้าเราไม่ใช้ Pipe และเขียนเป็น Loop ปกติ ก็น่าจะอารมณ์แบบตัวอย่างด้านบนเลย จะเห็นได้ว่าเขียนเยอะมาก ๆ ไม่ได้เป็น Functional มากสักเท่าไหร่ ไม่น่ารักเลย หรืออีกวิธี ถ้าเราไม่อยากเขียนยาว ๆ แบบนี้เราก็สามารถใช้ Map Function กับ Anonuymous Function ได้เหมือนกัน ถ้าอยากลองก็ไปลองกันได้เด้อ เราไม่ได้เขียนให้ดู

>>> adult_people
<generator object where.<locals>.<genexpr> at 0x100ae6c10>

กลับมาที่ Pipe ของเราต่อ เมื่อครู่ เราได้ Pipe เพื่อเลือกอายุที่มากกว่า 18 ออกมา แต่เมื่อเราเรียกเอ๋ ทำไมมันไม่เป็นเหมือนที่เราคิดละ ทำไมเราไม่ได้ List ของข้อมูลออกมาละ กลายเป็น Generator ซะงั้น ใช่แล้วฮ่ะ มันได้ออกมาเป็น Generator การใช้งานก็จะเหมือนการใช้ Generator ทั่ว ๆ ไปเลย มันก็มีข้อดีอยู่นะเอาจริง ๆ โดยเฉพาะเมื่อเราทำงานกับข้อมูลขนาดใหญ่ จะเก็บผลทั้งหมดลง Memory เลย ก็น่าจะไม่ไหวนะ เปลืองทั้งเงินซื้อ RAM และ เสียเวลามาก ๆ

>>> list(adult_people)
[20, 24, 26, 19, 19, 29, 24, 30, 20, 22, 29, 24, 35, 33, 27, 31, 32, 29, 30, 38, 35, 35, 34, 46, 34, 45, 35, 40, 36, 43, 53, 38, 54, 54, 49, 43, 54, 54, 58, 63, 54, 65, 67, 65, 54, 66, 57, 54, 61, 60, 71, 62, 68, 68, 64, 76, 83, 65, 77, 80, 80, 78, 73, 74, 76, 88, 78, 75, 85, 86, 89, 95, 89]

แต่ถ้าเรารู้อยู่แล้วว่าข้อมูลเราไม่ได้ใหญ่อะไรเลย เช่นในตัวอย่างของเราที่มีอย่างมากแค่ 80 ตัวเท่านั้น การเอามันออกมาทั้งหมดเลยไม่ใช่ปัญหาแน่นอน เราก็สามารถจับมัน Cast เป็น List แล้วเราก็จะได้ค่าใน Generator ทั้งหมดออกมาพร้อมใช้งานต่อได้เลย สะดวกมาก ๆ เลยชั่ยมั้ยล้าาาา

Handling Fu_king Large Data with Generator

from random import randint

def age_generator (sizing) :
    for _ in range(sizing) :
        yield randint(10,70)

แน่นอนว่า เวลาเราทำงานบางอย่างที่ Data ขนาดมันไม่น่ารักเท่าไหร่ โหลดเข้ามาคือแตกแน่นอน เกิน RAM ไปไกล ดังนั้น เราจะต้องใช้เทคนิคอื่นในการจัดการ ซึ่งแน่นอนว่าถ้าใครเคยทำงานกับ Data ขนาดใหญ่มาก่อนวิธีนึงที่เราทำได้คือ การใช้ Generator สิ่งที่เราทำก็เหมือนเดิมเลย คือ เราทำการ Random อายุของคนขึ้นมา ผ่านการเขียน Generator ที่เราสามารถกำหนดจำนวนของคนที่เราต้องการลงไปได้ แล้วเราก็ For-Loop แล้วค่อย ๆ Yield อายุออกไปทีละรอบเลย

adult_people = age_generator(200) | where (lambda x : x>18)

จากนั้น แทนที่เราจะยัด List เข้าไปตรง ๆ เราก็ยัด Generator เข้าไปตรง ๆ ได้เลย เอาจริง ๆ มันต้องทำได้อยู่แล้วนะ เพราะความเป็นจริงแล้ว List และ Generator เป็นพวก Iterable อยู่แล้ว หมายความว่า มันเป็น Object ที่สามารถ Loop ใส่มันได้อะไรประมาณนั้น การใช้ท่า Generator ก็จะทำให้การทำงานกับ Data ขนาดใหญ่สบายขึ้นไปอีก

แต่ตัว Pipe ไม่ได้มี Built-in Function สำหรับการทำ Multiprocessing มาให้เราเลยนะ ถ้าอยากได้ เราก็สามารถเขียนเองได้เหมือนกัน เราว่าถ้าทำออกมาจริง ๆ มันจะ Powerful มาก ๆ ในการทำงาน

Groupping Data

อีกเคสที่เราว่าน่าสนใจคือ การ Group Data จากเงื่อนไขต่าง ๆ เช่นถ้าเราทำงานกับ Data ที่ไม่ได้ใหญ่มากเท่าไหร่ อยากทำงานทดลองคิดไว ๆ การใช้ Pipe ก็ทำให้เราทดลองไอเดียได้เร็วมาก ๆ เหมือนกัน

filtered_data = age_generator(200) | groupby(lambda x: "Even" if x %2 == 0 else "Odd") | select(lambda x: {x[0]: list(x[1])})
print(list(filtered_data))

จากตัวอย่างด้านบน เราขอใช้ Generator เดิมเลยละกัน เป็น age_generator แต่หลัก ๆ ก็คือมัน Random ตัวเลขทั่ว ๆ ไปไม่มีอะไร เป้าหมายของเราคือ เราต้องการแยก เลขคู่ ออกจากเลขคี่ ซึ่งใน Pipe ก็จะมีคำสั่งชื่อ groupby มาให้เราใช้งานกัน ในนั้นเราก็เหมือนเดิมเลย ใช้ Anonymous Function ง่าย ๆ เช็คแค่ว่า Modulo กับ 2 แล้วมีเศษมั้ย แล้วก็แยกไปตามฟากได้เลย แต่ถ้าเราทำแค่นี้ เราจะได้ Dictionary ที่ Data เป็น Generator โดยเราสามารถเข้าไป Loop และแปลงเป็น List เองก็ได้ หรือเราก็ใช้ Pipe ให้เป็นประโยชน์ ก็แปลงมันไปเลยดิ แล้วค่อยแปลงอีกทีตอนเราจะใช้มันก็จะเรียกทั้งหมดเอง ง่ายมาก ๆ เลย

สรุป

Pipe เป็น Package ที่มันเจ๋งอยู่นะ มันไม่ได้มาแทนที่สิ่งที่ Python ไม่เคยมี จริง ๆ แล้วทั้งหมดที่เราเล่ามาเราเขียน Python เปล่า ๆ เลยไม่ได้ลง Package อะไรเลยมันก็ทำได้ แต่แค่มันเสียเวลา กับมันดูรกเท่านั้นเอง ทำให้ประโยชน์ของ Pipe ที่เราว่ามันเจ๋งจริง ๆ คือ เรื่องของเวลา และ ความสะอาด เข้าใจง่ายของ Code ดูเป็น Functional มากขึ้นเท่านั้นเอง ซึ่งเราแนะนำเลย โดยเฉพาะถ้าเราต้องทำงานกับพวก Pipeline ต่าง ๆ มันเป็นอะไรที่น่าสนใจมาก ๆ

Read Next...

สร้าง Book Tracking Library ด้วย Obsidian

สร้าง Book Tracking Library ด้วย Obsidian

เราเป็นคนที่อ่านกับซื้อหนังสือเยอะมาก ปัญหานึงที่ประสบมาหลายรอบและน่าหงุดหงิดมาก ๆ คือ ซื้อหนังสือซ้ำเจ้าค่ะ ทำให้เราจะต้องมีระบบง่าย ๆ สักตัวในการจัดการ วันนี้เลยจะมาเล่าวิธีการที่เราใช้ Obsidian ในการจัดการหนังสือที่เรามีกัน...

Garbage Collector บน Python ทำงานอย่างไร

Garbage Collector บน Python ทำงานอย่างไร

หากเราเรียนลงลึกไปในภาษาใหม่ ๆ อย่าง Python และ Java โดยเฉพาะในเรื่องของการจัดการ Memory ว่าเขาใช้ Garbage Collection นะ ว่าแต่มันทำงานยังไง วันนี้เราจะมาเล่าให้อ่านกันว่า จริง ๆ แล้วมันทำงานอย่างไร และมันมีเคสใดที่อาจจะหลุดจนเราต้องเข้ามาจัดการเองบ้าง...

ติดตั้ง Zigbee Dongle บน Synology NAS กับ Home Assistant

ติดตั้ง Zigbee Dongle บน Synology NAS กับ Home Assistant

ก่อนหน้านี้เราเปลี่ยนมาใช้ Zigbee Dongle กับ Home Assistant พบว่าเสถียรขึ้นเยอะมาก อุปกรณ์แทบไม่หลุดออกจากระบบเลย แต่การติดตั้งมันเข้ากับ Synology DSM นั้นมีรายละเอียดมากกว่าอันอื่นนิดหน่อย วันนี้เราจะมาเล่าวิธีการเพื่อใครเอาไปทำกัน...

โหลด CSV วิธีไหนเร็วที่สุด ?

โหลด CSV วิธีไหนเร็วที่สุด ?

เมื่อหลายวันก่อนมีพี่ที่รู้จักกันมาถามว่า เราจะโหลด CSV ยังไงให้เร็วที่สุด เป็นคำถามที่ดูเหมือนง่ายนะ แต่พอมานั่งคิด ๆ ต่อ เห้ย มันมีอะไรสนุก ๆ ในนั้นเยอะเลยนี่หว่า วันนี้เราจะมาเล่าให้อ่านกันว่า มันมีวิธีการอย่างไรบ้าง และวิธีไหนเร็วที่สุด เหมาะกับงานแบบไหน...