#100DaysOfPyCon2018 Day3: Dataclasses: The code generator to end all code generators

#100DaysOfPyCon2018 Day3: Dataclasses: The code generator to end all code generators
Photo by Chris Ried / Unsplash

Key takeaways

  • Sphinx ก็เอามาใช้ทำ Presentation ได้ แถมได้ document ที่อ่านง่ายกลับไปดูทีหลังได้ด้วย
  • Code generator: tools that write code for you based on specification
  • dataclasses มี learning curve ต่ำมาก ถ้ามองสามารถมองได้สองมุมคือ data holder เหมือน namedTuple หรือเป็น boilerplate เอาไว้เขียน class
  • ประวัติศาสตร์แบบย่อๆ เริ่มต้นเรามี dict, tuple, hand-written class หลังจากนั้น namedTuple 🎉✨ ก็เกิดขึ้นแล้วตามมาด้วย types.SimpleNamespace ทำให้เราสร้าง data structure ได้ง่ายขึ้น (access ได้ง่ายขึ้นด้วย) ในอีกมุมนึง ORMs ก็กำเนิดขึ้นด้วยจาก Django, SQLAlchemy, PeeWee ซึ่งใช้ class เป็นเทคนิคในการสร้าง data structure หลังจากนั้นมี traitlets เกิดขึ้นเป็น package ไว้ใช้ทำ data validation โดยใช้ class attribute เป็นตัวกำหนด พอ Python 3.6 ออกก็เกิด Type Annotation, Variable Annotation ช่วยให้เราสามารถ define type ของ attribute ของ class ได้เลย ท้ายที่สุดเรามี library ชื่อ attrs เป็นแรงบันดาลใจในการสร้าง dataclass
  • สามารถมองง่ายๆ ได้ว่าเป็น “Mutable namedtuples with defaults”
  • Dataclass เบสิกเลยเขียนคล้าย namedTuple มาก ต่างกันแค่ dataclass ใช้ decorator dataclass แต่ NamedTuple ต้อง inheritance ออกมาจาก NamedTuple class

ความสามารถของ Dataclass

  • สร้าง repl ให้เราโดยอัตโนมัติจาก attribute definition เลย
  • ใช้ replace() ในการ mutable attribute ได้ เช่น replace(c, hue=120) ถ้าเป็น namedTuple ต้องใช้ c._replace(hue=120) เพื่อป้องกัน namespace collision
  • ใช้ asdict() หรือ astuple() ให้คืนค่าออกมาเป็น dict หรือ tuple ได้เลย ข้อสังเกตุของ asdict() คือ dataclass จะคืน Dict ออกมาให้เลยในขณะที่ namedTuple จะคืน OrderedDict เพราะเป็น implementation เก่า
  • มี method __annotations__ เอาไว้ดู type annotation ของ attributes ได้
  • ข้อเสียของ dataclass คือ unpack ของได้ยากกว่า namedTuple (เพราะ implementation ข้างล่างสุดเป็น Dict) ทำให้ก่อน unpack ต้องแปลงเป็น tuple ก่อน
  • ในเรื่องของ Performance / Resource ตัว dataclass จะมีขนาดใหญ่กว่า namedTuple แต่แลกมาด้วยความเร็วในการ access object ที่เร็วกว่า
  • Dataclass สร้าง docstring, __repr__, __eq__ ให้เราโดยอัตโนมัติจาก attribute ที่เรา define ไว้แต่ไม่สร้าง __hash__ ให้นะ
  • ถ้าเราใส่ option frozen = True ใน dataclass decorator จะเป็นการบอกว่า dataclass นี้เป็น immutable หรือถ้ามองง่ายๆ คือให้มันทำตัวเป็น namedTuple
  • ใส่ option order = True ได้ด้วยแต่ผมฟังแล้วไม่ค่อยเข้าใจชัดเจนว่าตกลงมัน order ของอะไรกันแน่

Customize Fields Specification

นอกจากจะกำหนดพฤติกรรมของ dataclass ได้จาก decorator แล้วเรายังสามารถใช้ฟังก์ชั่น field() ในการกำหนดพฤติกรรมของแต่ละ attribute ได้ด้วย ตัวอย่างข้างบนเป็น use case คล้ายๆ ของจริงที่ต้องการสร้าง data structure ของ employee ขึ้นมา แล้วเก็บข้อมูลต่างๆ ในนี้ใช้ความสามารถของ field() หลากหลายมาก

  • เราสามารถสร้าง default_factory ได้ผ่าน option: default_factory ในเคสนี้เป็นการสร้าง list เปล่าให้กับ viewed_by
  • เราสามารถสร้าง custom method ได้เหมือน class ปกติทั่วไป ในเคสนี้คือ เมธอด access()
  • เราสามารถ exclude บาง field ออกจากการ hash ได้โดยกำหนด hash=False ในเคสนี้คือ salary กับ age จะไม่สามารถเปลี่ยนแปลงค่าได้หรือ immutable นั่นเอง
  • เราสามารถ exclude field ให้มันแสดงใน repl ได้ใช้ repr=False ในเคสนี้คือเราไม่อยากแสดง salary เวลา print ออกมา
  • เราสามารถ exclude field ไม่ให้ต้อง compare ได้มีประโยชน์เวลากัน attribute ที่เป็น complex number หรือ function ที่ไม่สามารถ order ได้ออกไป สามารถกำหนดได้โดยใช้ compare=False
  • ข้อมูลบางอย่างอาจจะต้องมีคำอธิบายเช่น เงินเดือนเป็นหน่วยอะไร หรือ field นี้มีความหมายว่าอะไร เราสามารถใส่ข้อมูลพวกนี้ลงไปใน metadata ได้เหมือนเคส salary ข้างบน

จริงๆ ในช่วงท้ายมีพูดถึง slots ด้วยแต่ผมฟังไม่ค่อยเข้าใจ รู้แค่ว่ามันจะ optimize ให้เรา access ของได้เร็วขึ้น กับเรื่อง __post_init__() ที่ไม่สามารถใช้ได้ อะไรประมาณนี้

วันก่อนผมไปเจอ blog ของ RealPython เขียนเรื่อง dataclass ไว้พอดี อธิบายไว้ดีพอสมควรเลยครับ รวมถึงเรื่อง slots ด้วยสนใจก็ไปอ่านต่อกันได้

Data Classes in Python 3.7+ (Guide) – Real Python
Data classes are one of the new features of Python 3.7. With data classes you do not have to write boilerplate code to get proper initialization, representation and comparisons for your objects.

Original post at: https://yothinix.medium.com/100daysofpycon2018-day3-dataclasses-the-code-generator-to-end-all-code-generators-694b9db7530a