Taking too long? Close loading screen.

คำสั่งแบบ Switch-Case Statements จะสามารถใช้ร่วมกับ Python ได้แล้ว!

Jul 31, 2022
Python คำสั่ง

Python คำสั่ง

เวอร์ชั่นที่ออกมาใหม่ล่าสุดเผยให้เห็น New Logic (ตรรกะแบบใหม่)

Python 3.10 เริ่มจะเต็มไปด้วยฟีเจอร์ใหม่ ๆ น่าทึ่งหลายอย่าง มีฟีเจอร์หนึ่งที่น่าสนใจมาก — Structural Pattern Matching (การเทียบเคียงรูปแบบแบบมีโครงสร้าง) — หรือที่พวกเรารู้จักกันคือ switch/case statement ซึ่ง Switch-statement ห่างหายไปจาก Python มานานแม้ว่าจะเป็นฟีเจอร์ทั่วไปของเกือบทุกภาษา

ย้อนกลับไปปี 2006 ที่มีการสร้าง PEP 3103 ขึ้น โดยแนะนำให้ดำเนินการตามคำสั่ง Switch-case Statement แต่หลังจากทำแบบสำรวจที่ PyCon 2007 หรืองานสัมมนาเกี่ยวกับภาษาที่ใช้เขียนโปรแกรม พบว่าฟีเจอร์ดังกล่าวไม่ได้รับการสนับสนุนผู้พัฒนา Python จึงล้มเลิกการพัฒนาฟีเจอร์นี้ไป ในปี 2020 และ Guido van Rossum (กวีโด แวน รอสซัม) ผู้สร้าง Python นำเสนอเอกสารกำกับโปรแกรมฉบับแรกภายใต้หัวข้อ Switch-statement แบบใหม่ ที่ถูกตั้งชื่อว่า Structural Pattern Matching ตามที่พบใน PEP 634

โดยสิ่งที่เรามีในตอนนี้เป็นมากกว่าแค่ Switch-case Statement แบบเรียบง่าย  ซึ่งเดี๋ยวเราจะได้เห็นกันในบทความนี้

มาดูกันว่าตรรกะแบบใหม่นี้ทำงานอย่างไร

> Structural Pattern Matching
  - Intro
  - Another Example
  - Real Use-Case With JSON

Structural Pattern Matching

Pattern Matching ใช้ค่าตัวเลขหลังจาก match และช่วยให้เราเขียนเคสที่อาจมีออกมาหลายกรณี โดยแต่ละกรณีจำกัดความว่าเป็น case ที่เท่าไหร่ และถ้าเราต้องจับคู่ระหว่าง Match และ Case หรือ match-case เราจะต้องใช้งานโค้ดตามลำดับ

ตัวอย่างเช่น:

http_code = "418"

match http_code:
    case "200":
        print("OK")
        do_something_good()
    case "404":
        print("Not Found")
        do_something_bad()
    case "418":
        print("I'm a teapot")
        make_coffee()
    case _:
        print("Code not found")

ในส่วนนี้เราต้องตรวจดูเงื่อนไขหลายอย่าง รวมถึงการดำเนินการปฏิบัติการที่แตกต่างกัน โดยขึ้นอยู่กับค่าตัวเลขที่เราพบภายใน http_code

จากแผนผังในด้านบน จะเห็นได้ชัดในทันทีว่าเราสามารถสร้างตรรกะเดียวกันโดยใช้กลุ่มของ If-elif-else Statement:

http_code = "418"

if http_code == "418":
    print("OK")
    do_something_good()
elif http_code == "404":
    print("Not Found")
    do_something_bad()
elif http_code == "418"
    print("I'm a teapot")
    make_coffee()
else:
    print("Code not found")

อย่างไรก็ตาม เราสามารถใช้ Match-case Statement ลบการทำซ้ำของ http_code == ออก ซึ่งเมื่อทดสอบกับหลากหลายเงื่อนไขจะให้ผลลัพธ์ที่ดูง่ายกว่า

อีกหนึ่งตัวอย่างของ Match-case Statement

เราจะศึกษาตัวอย่างที่ดีของการใช้ Match-case Statement เพื่อปรับปรุงความสามารถในการอ่านโค้ดใน PEP 635 หนึ่งในนั้นคือตัวอย่างนี้ ซึ่งแสดงให้เราเห็นวิธีใช้ Match-case เพื่อตรวจดูประเภทและโครงสร้างของตัวทดสอบของเรา:

match x:
    case host, port:
        mode = "http"
    case host, port, mode:
        pass

ในส่วนนี้เรามักจะคาดหวังที่จะได้รายละเอียดการเชื่อมโยงในรูปแบบ Tuple (ทูเพิล) และมอบหมายค่าตัวเลขที่ให้มากับตัวแปรที่ถูกต้อง ซึ่งถ้า mode การเชื่อมโยงยังไม่ถูกกำหนดภายใน Tuple (ตัวอย่างเช่น มีเพียงค่าตัวเลขสองค่าที่ให้มาคือ host และ port) เราสันนิษฐานได้ว่าโหมดการเชื่อมโยงคือ “http”.

อย่างไรก็ตามในกรณีอื่น ๆ เราอาจคาดการณ์ได้ว่าโหมดถูกกำหนดไว้แล้วอย่างชัดเจน เราจึงอาจจะได้รับ Tuple แบบ (<host>, <port>, "ftp") — ซึ่งในกรณีนี้เราไม่ได้อยากตั้ง mode เป็น “http”

และถ้าเราอยากจะเขียนตรรกะเดียวกันโดยใช้ If-else Statement เราจะได้สิ่งนี้:

if isinstance(x, tuple) and len(x) == 2:
    host, port = x
    mode = "http"
elif isinstance(x, tuple) and len(x) == 3:
    host, port, mode = x

การเลือกใช้ของแต่ละคนอาจจะแตกต่างกันตามความ แต่สำหรับผมแล้วการใช้งาน Match-case ดูได้สบายตากว่ามาก

กรณีศึกษาของ JSON

อีกกรณีศึกษาหนึ่งที่ดูน่าสนใจคือความสามารถในการแยกวิเคราะห์คำในพจนานุกรมที่แตกต่างกันตามโครงสร้างของมัน กรณีทดสอบที่ดีของเรื่องนี้คือการแยกวิเคราะห์ชุดข้อมูล SQuAD 2 โดยชุดข้อมูล SQuAD 2 เป็นชุดถาม-ตอบที่เป็นที่นิยมมาก ซึ่งใช้ในการฝึกโมเดลเรียนรู้ของเครื่องจักรสำหรับการถาม-ตอบ เราสามารถดาวน์โหลดข้อมูลได้ด้วย:

ถ้าเรามาลองดูโครงสร้างของ SQuAD จะเห็นชัดว่ามีหลากหลายระดับ ซึ่งเราจะต้องพิจารณาเมื่อทำการแยกวิเคราะห์:

รูปแบบ JSON ของชุดเทรนนิ่ง SQuAD 2

แต่ปัญหาคือ ไม่ใช่ว่าทุกตัวอย่างจะสามารถใช้รูปแบบพจนานุกรมแบบเดียวกันได้ ถ้าเราดูสองสามตัวอย่างสุดท้าย เราจะเห็นรายการ qas มีทั้ง answers และ plausible_answers — ขณะที่ตัวอย่างมีเพียงแค่ answers:

การกรอกข้อมูลสุดท้ายในชุดเทรนนิ่ง SQuAD 2 JSON แสดงให้เห็นรูปแบบพจนานุกรมที่แตกต่างกัน (ซึ่งการกรอกข้อมูลอื่นๆ มากมายทั่วไฟล์ใช้แบบเดียวกัน)

ทีนี้ลองมาใช้ Match-case Statement แบบใหม่เพื่อสร้างทางเลือกที่สบายตากว่าสำหรับตรรกะหนัก ๆ แบบ if-else ที่จำเป็นต้องใช้กับสิ่งนี้  อย่างแรก เราต้องโหลดข้อมูลมาก่อน:

เราโหลดข้อมูลโดยใช้ json.load

SQuAD JSON มีหลายระดับชั้น  หลังจากเข้าถึง squad['data']  เราจำเป็นต้องทำซ้ำในคำถามแต่ละ group: จากนั้นในแต่ละ paragraph แล้วในแต่ละ qas (คำถาม-คำตอบ) — ซึ่งดูเหมือน:

for group in squad['data']:
    for paragraph in group['paragraphs']:
        for qa in paragraph['qas']:
            # insert code here

และนี่คือจุดที่เริ่มสนุกแล้วล่ะ การใช้ตรรกะแบบ if-else เราจะได้อะไรแบบนี้:

แม้ว่ามันจะดูไม่ค่อยสวย แต่มันก็สามารถใช้งานได้ ลองมาเขียนใหม่โดยใช้ตรรกะแบบ match-case ดูบ้าง:

จะเห็นได้ว่า การใช้ ตรรกะนี้จะช่วยให้ดูซับซ้อนน้อยลงและถือเป็นอีกหนึ่งทางเลือกที่ดีเมื่อเทียบกับเวอร์ชั่นดั้งเดิมที่ใช้ตรรกะการแยกวิเคราะห์

ทั้งหมดมีแค่นี้เป็นเรื่องของ Structural Pattern Matching แบบใหม่ที่นำเสนอใน Python 3.10! แบบสั้น ๆ เท่านั้น เวอร์ชั่นเต็มคาดว่าจะออกมาในต้นเดือนตุลาคม 2021

ส่วนตัวแล้ว ผมคิดว่า Syntax แบบใหม่นี้ดูดีมาก ๆ — แม้ว่าตอนนี้จะมั่นใจได้แค่ 50/50 แต่เมื่อมีผู้ใช้ match-case ทำโค้ดมากขึ้น ผมมั่นใจว่าพวกเขาจะเลือกวิธีการที่ดีที่สุดในการเขียน

บทความโดย James Briggs
เนื้อหาจากบทความของ Medium
แปลและเรียบเรียงโดย ไอสวรรค์ ไชยชะนะ
ตรวจทานและปรับปรุงโดยนววิทย์ พงศ์อนันต์

Isawan Chaichana

Translator

Navavit Ponganan

Senior Data Scientist Government Big Data Institute (GBDi)

Sign up to join Big Data Community Thailand

Make comments, write articles, and contribute to our community.