51 คะแนน โดย GN⁺ 2025-04-24 | 5 ความคิดเห็น | แชร์ทาง WhatsApp
  • แนะนำ ฟีเจอร์ขั้นสูง 14 อย่าง ของ Python ที่คนมักไม่ค่อยรู้จัก พร้อมตัวอย่างใช้งานจริง
  • อธิบายเชิงลึกเกี่ยวกับ static typing และการออกแบบเชิงโครงสร้าง เช่น typing, generics, protocols, context managers
  • รวมถึง structural pattern matching ที่เพิ่งเพิ่มเข้ามาตั้งแต่ Python 3.10 ขึ้นไป และเทคนิคเพิ่มประสิทธิภาพอย่าง slots และ metaclass
  • มี เคล็ดลับสำหรับการเขียนโค้ดให้สะอาดขึ้น เช่น f-string, cache, future, proxy, for-else, walrus
  • ในแต่ละฟีเจอร์มี ลิงก์และเอกสารอ้างอิงสำหรับศึกษาต่อ พร้อมการนำเสนอที่แม้นักพัฒนาระดับจูเนียร์ก็เข้าถึงได้ง่าย

สรุป 14 ฟีเจอร์ขั้นสูงของ Python

# การโอเวอร์โหลดไทป์

  • ตัวตกแต่ง @overload ช่วยให้ กำหนด type signature ได้หลายแบบในฟังก์ชันเดียว
  • type checker สามารถ อนุมานชนิดค่าที่คืนกลับได้อย่างแม่นยำ ตามค่าของอาร์กิวเมนต์ที่ส่งมา
  • ใช้ Literal เพื่อ จำกัดค่าของสตริง ได้ด้วย
  • สามารถทำ signature ของฟังก์ชันที่บังคับให้รับ id หรือ username อย่างใดอย่างหนึ่ง ได้
  • ใช้ Literal เป็นทางเลือกแทน Enum แบบเบาสำหรับความปลอดภัยของชนิดข้อมูล

# อาร์กิวเมนต์แบบ keyword-only / positional-only

  • ใช้ * เพื่อกำหนดให้เป็น อาร์กิวเมนต์แบบ keyword-only (ห้ามใช้เป็น positional argument)
  • ใช้ / เพื่อกำหนดให้เป็น อาร์กิวเมนต์แบบ positional-only (ห้ามใช้เป็น keyword argument)
  • ช่วย บังคับรูปแบบการใช้อาร์กิวเมนต์ให้ชัดเจน ในการออกแบบ API

# Future Annotations (__future__)

  • เดิมที type hint จะถูกประเมินทันทีใน runtime จึงเกิด ปัญหาเรื่องลำดับการประกาศ
  • สามารถ เลื่อนเวลาการประเมิน ได้ด้วย from __future__ import annotations
  • แต่เนื่องจากใช้วิธีจัดการแบบสตริง จึงต้องระวังเมื่อใช้งาน type ใน runtime
  • PEP 649 เสนอการปรับปรุงโดยใช้การประเมินแบบหน่วงเวลาในแอตทริบิวต์ __annotations__

# ไวยากรณ์ Generic

  • ตั้งแต่ Python 3.12 เป็นต้นไป รองรับ ไวยากรณ์ใหม่สำหรับการนิยาม generic type
  • ใช้งานได้เข้าใจง่ายกว่าเดิมในรูปแบบ class Foo[T, U: int] แทน TypeVar
  • มี Variadic Generics เพิ่มเข้ามาเพื่อรองรับการจัดการชนิดข้อมูลที่หลากหลาย
  • การประกาศ type alias ก็สั้นลง เช่น type Vector = list[float]

# Protocols

  • เป็นเวอร์ชันตรวจสอบชนิดของ Duck Typing ที่ทำให้ใช้ structural subtyping ได้
  • หากคลาสมีเมธอดที่กำหนดไว้ ก็สามารถเข้ากันได้ทางชนิดข้อมูลแม้ไม่สืบทอด type โดยตรง
  • สามารถขยายให้ตรวจด้วย isinstance ได้ผ่าน @runtime_checkable

# Context Manager

  • เป็นอ็อบเจ็กต์ที่มีเมธอด __enter__, __exit__ และใช้งานในบล็อก with
  • สามารถสร้างแบบฟังก์ชันอย่างง่ายได้ด้วยตัวตกแต่ง contextlib.contextmanager
  • ทำ งานตั้งค่าและงานเก็บกวาด ก่อนและหลัง yield

# Structural Pattern Matching

  • ใช้ไวยากรณ์ match-case เพื่อ แตกแขนงการทำงานกับโครงสร้างข้อมูลที่ซับซ้อนได้อย่างเข้าใจง่าย
  • รองรับการแยกโครงสร้าง tuple/list, OR pattern, guard condition (if) และ wildcard
  • เนื่องจากแยกเงื่อนไขตามโครงสร้างของข้อมูล จึง ช่วยเพิ่มความอ่านง่ายและการดูแลรักษาโค้ด

# การปรับแต่งประสิทธิภาพด้วย __slots__

  • ใช้สล็อตแบบคงที่แทน __dict__ เพื่อปรับปรุงหน่วยความจำและความเร็ว
  • __slots__ ใช้ tuple ที่ระบุเฉพาะชื่อแอตทริบิวต์
  • ป้องกันการเพิ่มแอตทริบิวต์ที่ไม่จำเป็นในคลาส
  • แต่เป็นการปรับแต่งระดับไมโคร จึงควรใช้อย่างระมัดระวัง

# รวมเคล็ดลับสไตล์โค้ด Python

  • คำสั่ง for-else: หากลูปจบโดยไม่มี break จะทำงานส่วน else
  • walrus operator (:=): ประกาศตัวแปรและตรวจสอบได้พร้อมกัน
  • or short-circuit evaluation: คืนค่าที่เป็นจริงตัวแรกจากหลายค่า
  • การเชื่อม comparison operator: เขียนโค้ดให้กระชับได้ เช่น 0 < x < 10

# การฟอร์แมตขั้นสูงของ f-string

  • ใช้รูปแบบ f"{ตัวแปร=}" เพื่อ แสดงผลสำหรับดีบัก ได้
  • มีตัวเลือกหลากหลาย เช่น ฟอร์แมตตัวเลข (:.2f, :+.2f, :,) และฟอร์แมตวันที่ (%Y-%m-%d)
  • ใช้ format mini-language สำหรับการจัดกึ่งกลาง การเติมช่องว่าง และการแสดงเปอร์เซ็นต์

# ตัวตกแต่งแคช

  • ใช้ @lru_cache และ @cache เพื่อ เก็บผลลัพธ์ของฟังก์ชัน และเพิ่มความเร็ว
  • มีประโยชน์กับฟังก์ชันเวียนเกิดหรือการคำนวณซ้ำจำนวนมาก
  • @cache ถูกเพิ่มเข้ามาตั้งแต่ Python 3.9 และมีแคชไม่จำกัดเป็นค่าเริ่มต้น

# Python Future

  • เป็น อ็อบเจ็กต์สำหรับจัดการงานอะซิงก์ คล้าย Promise ของ JS
  • จัดการผลลัพธ์แบบอะซิงก์ได้ด้วย Future.set_result(), add_done_callback() เป็นต้น
  • asyncio.Future() สามารถใช้ร่วมกับ await ได้
  • เมื่อใช้ร่วมกับ ThreadPoolExecutor ก็สามารถทำ งานขนานเบื้องหลัง ได้

# Proxy Property

  • ทำให้แอตทริบิวต์ของคลาสหนึ่งตัว ทำงานได้ทั้งเหมือนพร็อพเพอร์ตีและเหมือนฟังก์ชัน
  • ใช้ __get__, __call__, __repr__ เพื่อให้มีความสามารถทั้งสองแบบ
  • ช่วยให้การออกแบบ API จัดการทั้งค่าเริ่มต้นและการเรียกพร้อมพารามิเตอร์ในรูปแบบเดียวกัน ได้
  • มีคุณค่าในเชิงตัวอย่างเชิงทดลองมากกว่าการใช้งานจริง

# Metaclass

  • คือ คลาสของคลาส ที่ใช้สร้างตัวคลาสขึ้นมาเอง
  • สามารถใส่เมตะลอจิก เช่น การปรับแต่งแอตทริบิวต์ของคลาสหรือการลงทะเบียนอัตโนมัติ
  • ในทางปฏิบัติ ส่วนใหญ่ แทนที่ได้ด้วยตัวตกแต่ง
  • ใน Django, SQLAlchemy, Pydantic เป็นต้น มีการใช้ metaclass ภายใน

5 ความคิดเห็น

 
hackerpropoker 2025-04-29

จากมุมมองของฝั่งแบ็กเอนด์ ผมเคยมีประสบการณ์ว่า metaclass ทำให้การดีบักยากขึ้น

 
ilotoki0804 2025-04-28

มีความเห็นว่า for-else ไม่ได้ช่วยให้โค้ดอ่านง่ายหรือชัดเจนขึ้นมากนัก จึงมักถูกมองว่าเป็น anti-pattern และโปรดทราบว่า asyncio.Future ถือเป็นรายละเอียดการติดตั้งใช้งานภายในของ asyncio

 
dkmin 2025-04-26

ขอบคุณครับ โดยเฉพาะข้อ 10 จะเอาไปใช้ทันที

เพิ่มกฎการเขียนโค้ดด้วย AI..

 
yangeok 2025-04-25

ขอบคุณสำหรับเคล็ดลับดี ๆ

 
GN⁺ 2025-04-24
ความคิดเห็นจาก Hacker News
  • สวัสดี! ผมเป็นผู้เขียนบล็อกต้นฉบับเอง! ตกใจมากที่เห็นบทความของตัวเองขึ้นหน้าแรกของ HN ตอนตี 4

    • บทความนี้เริ่มต้นจากทวีตสั้น ๆ 14 ข้อที่เขียนไว้หนึ่งเดือนก่อนเริ่มบล็อก
    • ตอนเริ่มบล็อก ผมจึงตัดสินใจนำทวีตเหล่านี้มาใช้ซ้ำเป็นโพสต์แรก
    • เพราะแบบนั้น ลำดับการเล่าอาจดูแปลก ๆ อยู่บ้าง
    • วันจันทร์ผมพยายามหาเรื่องที่มีประโยชน์ ส่วนวันศุกร์ก็พยายามหาอะไรที่แปลกขึ้นมาหน่อย
    • ชื่อบทความก็เช่นกัน เป็นการรวบรวมฟีเจอร์ 14 อย่างที่ผมรู้สึกว่าน่าสนใจระหว่างใช้ Python
    • ผมใช้เวลาคิดชื่อเรื่องแค่ประมาณ 5 วินาที
  • ทุกครั้งที่ใช้ Python ผมจะกังวลว่าโค้ดจะดูเหมือนใช้ Python ผิดวิธีไหม

    • รู้สึกทึ่งกับรายละเอียดเชิงลึกหรือความเปลี่ยนแปลงของ Python ที่ตัวเองไม่เคยรู้มาก่อน
    • Go ให้ความมั่นใจว่าโค้ดจะไม่ล้าสมัยแม้เวลาจะผ่านไปหลายปี
    • เป็นบทความที่ยอดเยี่ยม
  • Python ก็ควรเป็น Python ต่อไป ส่วน golang, Rust, Typescript ก็ควรมีปรัชญาและการออกแบบของแต่ละภาษาเอง

    • เขียนโค้ดมา 28 ปีใน 4 ภาษา และไม่ชอบการเปลี่ยนแปลงของ Python
    • สาเหตุที่ Python ได้รับความนิยมไม่ใช่เพราะเลเยอร์เพิ่มเติมอย่าง type checking หรือ annotation
    • เคยเห็นสิ่งคล้ายกันในภาษาอื่นด้วย
    • นี่เป็นรายการที่ครอบคลุมของฟีเจอร์ที่เพิ่งถูกแนะนำในช่วงหลัง
    • ยังมีรายการเก่าก่อนหน้านี้ที่ผู้อ่านอาจมองว่ามีประโยชน์
  • ข้อดีที่ใหญ่ที่สุดของ Python คือมันให้ความรู้สึกเหมือน pseudocode ที่รันได้

    • ตัวภาษาไม่ได้ขัดจังหวะคำสั่งในระดับโดเมน
    • ยิ่งเพิ่มฟีเจอร์มากเท่าไร เสน่ห์ก็ยิ่งลดลง
    • คนส่วนใหญ่ไม่ได้เข้าใจ Python อย่างลึกซึ้ง
  • ข้อท้วงติงเกี่ยวกับหัวข้อ 9.3 การประเมินนิพจน์: ถ้ามีสตริงว่าง การประเมินผลจะต่างออกไป

    • ส่วน if-else จะถือว่าสตริงว่างเป็นค่าที่ใช้ได้ แต่ตัวดำเนินการ or จะถือว่าเทียบเท่ากับ None
  • ในฐานะคนที่ย้ายจาก Javascript/Typescript มา Python นี่เป็นแหล่งข้อมูลที่มีประโยชน์

    • typing overload มีไว้รองรับฟีเจอร์ที่ไม่น่าพึงประสงค์ของ Javascript และมองว่าเป็นหนี้ทางเทคนิค
    • keyword-only และ positional-only arguments มีไวยากรณ์ที่กระชับเกินไปจนกังวลเรื่องความอ่านง่าย
    • future annotations ช่วยได้มากในช่วงหลัง
    • protocol คล้ายกับ Typescript แต่ก็ไม่ค่อยให้ความรู้สึกแบบ Python
    • metaclass เป็นเครื่องมือทรงพลังที่แก้ปัญหาเฉพาะทางได้
  • ฟีเจอร์ส่วนใหญ่ไม่ใช่ฟีเจอร์ขั้นสูง

    • ผมมักหลีกเลี่ยง metaclass เพราะมันอาจนำไปสู่พฤติกรรมที่ซับซ้อน
    • 'พร็อกซีพร็อพเพอร์ตี' ไม่ใช่ฟีเจอร์
  • สิ่งที่อยากเปลี่ยนในรายการคือการใส่คอนเทนเนอร์ของ collections.abc เข้าไปด้วย

    • มีหลายคอมเมนต์ที่ไม่ชอบ walrus operator แต่พอเจอกรณีใช้งานที่ดีแล้วก็ใช้มันได้อย่างมีประโยชน์
    • เวลาใช้แพตเทิร์น regular expression โค้ดจะสะอาดขึ้นมาก
  • สนุกกับการได้อ่านบทความนี้

    • ฟีเจอร์ส่วนใหญ่เป็นฟีเจอร์ของโมดูล typing
    • ยังไม่ค่อยมั่นใจเรื่อง generic หรือ protocol
    • สงสัยว่าโค้ด Python ระดับ production สมัยใหม่ใช้ type กันทุกที่หรือไม่