คุณลักษณะ pattern matching ของ Python ที่เปิดตัวในเวอร์ชัน 3.10 มีช่องโหว่ที่ไม่คาดคิดซึ่งช่วยให้นักพัฒนาสามารถแฮ็ค match statements ผ่าน Abstract Base Classes (ABCs) ได้ การค้นพบนี้ได้จุดประกายการถกเถียงอย่างเข้มข้นในชุมชน Python เกี่ยวกับการตัดสินใจในการออกแบบกลไกการควบคุมการไหลของโปรแกรมที่ใหม่ล่าสุดของภาษานี้
ไทม์ไลน์ช่องโหว่ของ Python Pattern Matching
- Python 3.10: เปิดตัว pattern matching พร้อมคำสั่ง
match
/case
- Pattern matching ใช้การตรวจสอบ
isinstance()
ซึ่งเคารพเมธอด__subclasshook__
ของ ABC - ABC สามารถกำหนดตรรกะแบบกำหนดเองสำหรับการกำหนด subclass
- Python 3.8: เปิดตัว Protocols เป็นทางเลือกที่ปลอดภัยกว่าสำหรับ structural typing
- Python 2.6: ABC พร้อม
__subclasshook__
พร้อมใช้งานครั้งแรก (11 ปีก่อน Protocols)
ช่องทางลับใน Pattern Matching
ปัญหานี้เกิดจากวิธีที่ pattern matching ของ Python โต้ตอบกับ Abstract Base Classes และเมธอด __subclasshook__
ของพวกมัน เมธอดนี้ช่วยให้ ABCs สามารถกำหนดตรรกะแบบกำหนดเองสำหรับการตัดสินใจว่าคลาสใดนับเป็น subclass หรือไม่ แม้ว่าคลาสเป้าหมายจะไม่รู้จัก ABC นั้นเลยก็ตาม เมื่อ pattern matching ตรวจสอบ isinstance(obj, class)
มันจะเคารพ hooks แบบกำหนดเองเหล่านี้ ทำให้เกิดโอกาสสำหรับพฤติกรรมที่ไม่คาดคิด
นักพัฒนาสามารถสร้าง ABC ที่จับคู่ objects ตามเงื่อนไขที่กำหนดเองได้ - ไม่ว่าจะเป็นการมี attributes บางอย่าง ชื่อของพวกมันเป็น palindromes หรือแม้กระทั่งตาม input ของผู้ใช้ นี่หมายความว่า match statement ที่ดูเหมือนจะตรวจสอบ types เฉพาะอาจจะกำลังรันตรรกะที่แตกต่างกันโดยสิ้นเชิงเบื้องหลัง
Abstract Base Classes (ABCs): คลาสของ Python ที่กำหนด interfaces ที่คลาสอื่นควรจะ implement ช่วยให้มีการตรวจสอบ type ที่ยืดหยุ่นโดยไม่ต้องมีการสืบทอดอย่างชัดเจน
ความกังวลของชุมชนเกี่ยวกับการออกแบบภาษา
ชุมชน Python ได้แสดงความกังวลอย่างมีนัยสำคัญเกี่ยวกับพฤติกรรมนี้ โดยเฉพาะอย่างยิ่งเรื่องความสามารถในการอ่านและการบำรุงรักษาโค้ด นักพัฒนาหลายคนกังวลว่าคุณลักษณะนี้สร้าง spooky action at a distance ที่การ debug กลายเป็นไปไม่ได้เกือบจะเลยเมื่อ ABCs จากส่วนต่างๆ ของ codebase โต้ตอบกันอย่างไม่คาดคิด
การวิพากษ์วิจารณ์ในวงกว้างขยายไปถึงการ implement pattern matching ของ Python เอง ต่างจากภาษา functional ที่จัดการ pattern matching อย่างสง่างาม เวอร์ชันของ Python ได้รับการวิพากษ์วิจารณ์เรื่องพฤติกรรมที่ไม่สอดคล้องกันกับ variable scoping และการออกแบบที่เป็น statement-based แทนที่จะเป็น expression-based ชุมชนได้สังเกตว่าการ matching กับ constants เทียบกับ variables ให้ผลลัพธ์ที่แตกต่างกันอย่างมาก ทำลายความคาดหวังพื้นฐานเกี่ยวกับวิธีที่โค้ด Python ควรจะทำงาน
Variable scoping: วิธีที่ภาษาโปรแกรมกำหนดว่าตัวแปรสามารถเข้าถึงและแก้ไขได้ที่ไหนภายในโค้ด
ปัญหาที่ชุมชนระบุเกี่ยวกับ Pattern Matching ใน Python
- Variable Scoping: ตัวแปรรั่วไหลออกนอก match blocks ทำให้ผิดความคาดหวัง
- ความไม่สอดคล้องของ Syntax:
case 404
กับcase not_found
มีพฤติกรรมที่แตกต่างกันโดยสิ้นเชิง - Statement vs Expression: ต่างจาก Python ภาษาอื่น ๆ pattern matching ของ Python เป็นแบบ statement-based
- ความยืดหยุ่นที่จำกัด: ไม่สามารถใช้ตัวแปรโดยตรงได้หากไม่มีวิธีแก้ไขปัญหา
- การเยื้องสองชั้น: ต้องการระดับการเยื้องเพิ่มเติมเมื่อเปรียบเทียบกับโครงสร้างอื่น ๆ
- พฤติกรรมการ Cache: ผลลัพธ์ของ
__subclasshook__
ถูก cache ไว้ ทำให้จำกัดพฤติกรรมแบบไดนามิก
แนวทางทางเลือกและวิธีแก้ไขชั่วคราว
แม้จะมีศักยภาพในการใช้งานในทางที่ผิด สมาชิกบางคนในชุมชนเห็นการใช้งานที่ถูกต้องสำหรับฟังก์ชันนี้ คุณลักษณะนี้ช่วยให้เกิด structural typing - การตรวจสอบว่า objects implement interfaces บางอย่างหรือไม่โดยไม่ต้องมีการสืบทอดอย่างชัดเจน สิ่งนี้มีคุณค่าเป็นพิเศษก่อนที่ Python 3.8 จะแนะนำ Protocols ซึ่งให้วิธีที่ปลอดภัยกว่าในการบรรลุผลลัพธ์ที่คล้ายกัน
อย่างไรก็ตาม ความเห็นพ้องยังคงต่อต้านอย่างแรงการใช้เทคนิคเหล่านี้ในโค้ดที่ใช้งานจริง ชุมชนเน้นย้ำว่าแม้จะเป็นไปได้ทางเทคนิค แนวทางดังกล่าวละเมิดหลักการของความประหลาดใจที่น้อยที่สุดและทำให้โค้ดยากต่อการบำรุงรักษาและ debug อย่างมีนัยสำคัญ
การถกเถียง Pattern Matching ในวงกว้าง
การค้นพบนี้ได้จุดประกายการอภิปรายใหม่เกี่ยวกับตัวเลือกการออกแบบ pattern matching ของ Python นักพัฒนาหลายคนรู้สึกว่าคุณลักษณะนี้ถูก implement ได้แย่เมื่อเปรียบเทียบกับฟังก์ชันที่คล้ายกันในภาษาอื่น โดยอ้างถึงปัญหาเช่น ความต้องการ double indentation การสนับสนุน expression ที่จำกัด และกฎ syntax ที่ไม่สอดคล้องกัน
คุณลักษณะ pattern matching โดยรวมแล้วได้รับการออกแบบอย่างสมเหตุสมผลพอสมควร และผู้คนจะคาดหวังให้มันทำงานในแบบที่สมเหตุสมผล ในขณะที่ subclasshook เป็นเวทมนตร์ดำที่รุนแรงมาก
ปฏิกิริยาของชุมชนเน้นย้ำความกังวลที่เพิ่มขึ้นเกี่ยวกับการเพิ่มภาษาล่าสุดของ Python นักพัฒนาบางคนโต้แย้งว่าคุณลักษณะเช่น pattern matching เพิ่มความซับซ้อนโดยไม่ให้ประโยชน์ที่เป็นสัดส่วน โดยเฉพาะอย่างยิ่งเมื่อทางเลือกที่ง่ายกว่าเช่น dictionaries หรือ if statements มักจะเพียงพอ
แม้ว่าเทคนิคการแฮ็ค ABC นี้จะแสดงให้เห็นถึงความยืดหยุ่นของ Python แต่มันก็ทำหน้าที่เป็นเรื่องเตือนใจเกี่ยวกับผลที่ตามมาที่ไม่ได้ตั้งใจของการรวมคุณลักษณะภาษาที่ทรงพลัง คำแนะนำอย่างแรงของชุมชน Python ยังคงชัดเจน: หลีกเลี่ยงเทคนิคเหล่านี้ในโค้ดที่ใช้งานจริงเพื่อรักษาความสามารถในการอ่านและป้องกันฝันร้ายในการ debug