คำว่า Metaprogramming หมายถึงการเขียนโปรแกรมคอมพิวเตอร์ที่โปรแกรมคอมพิวเตอร์พยายามจัดการหรือมีความรู้เกี่ยวกับตัวมันเอง Python รองรับ metaprogramming สำหรับคลาสผ่านชนิดคลาสใหม่ที่เรียกว่า metaclass
Meta-programming ผ่าน metaclasses ใน Python คือการสร้างฟังก์ชันและคลาสที่จัดการโค้ดโดยการแก้ไข ห่อหุ้ม หรือสร้างโค้ดที่มีอยู่
คุณสมบัติหลักของ meta-programming คือ −
- Metaclasses
- Decorators
- Class-decorators
Metaclass คืออะไร
นิยามที่จำกัดของ metaclass สามารถเป็นได้ว่า คลาสที่สร้างคลาส Python เป็นภาษาเชิงวัตถุที่ทุกอย่างเป็นอ็อบเจกต์ และคลาสก็ไม่ใช่ข้อยกเว้น การกำหนดคลาสด้วยคีย์เวิร์ด class Python จริงๆ แล้ว execute มันแล้วสร้างอ็อบเจกต์ เนื่องจากเป็นอ็อบเจกต์ คุณจึงสามารถกำหนด คัดลอก เพิ่ม attribute เป็นพารามิเตอร์ฟังก์ชัน และอื่นๆ การใช้ metaclasses ช่วยให้เราควบคุมการสร้างคลาสได้ เช่น การแก้ไขคุณสมบัติของคลาส ตรวจสอบความถูกต้องของคุณสมบัติ และอื่นๆ
Python Built-in Metaclass
Metaclass ของทุกคลาสคือ type
class a: pass print(type(a))
ผลลัพธ์:
จากผลลัพธ์ข้างต้น เราเห็นว่า "a"(คลาส) เป็นอ็อบเจกต์ของคลาส type เรายังสามารถพูดได้ว่า "a"(คลาส) เป็น instance ของคลาส type ดังนั้น type จึงเป็น metaclass ใน Python ทุกคลาสเป็นของ built-in metaclass type

การใช้ Metaclass สร้างคลาส Python
ตามที่เราเห็นในตัวอย่างข้างต้น type เป็น default metaclass เราสามารถสร้างคลาสใหม่ด้วยความช่วยเหลือของ default metaclass นี้ (type) ได้
>>> class hello(object): pass
สามารถสร้างด้วยตนเองได้เช่นนี้ −
>>> hello = type('hello', (), {}) >>> print(hello)# คืนค่าคลาสอ็อบเจกต์ >>> print(hello()) # สร้าง instance ด้วยคลาส <__main__.hello object at 0x05D86830>
Type รับ dictionary เพื่อกำหนด attribute ของคลาส ดังนั้น
>>> class hello(object): world = True<โค้ดข้างต้นคล้ายกับ
hello = type('hello', (), {'world' : True})
สร้าง Metaclass
เมื่อไหร่ที่จะสร้าง metaclass? เมื่อฉันต้องการควบคุมการสร้างคลาส เช่น การตรวจสอบหรือแก้ไขคุณสมบัติของคลาส
กระบวนการ instantiate ของคลาส −
- สร้าง instance โดยเรียก __new__()
- เรียก __init__() เพื่อ initialize instance ที่สร้างข้างต้น
ดังนั้นเมื่อเราสร้าง custom metaclass เราจริงๆ แล้วเปลี่ยน __new__() หรือ __init__ method ของ parent class
ตัวอย่าง 1 − Metaclass ที่แก้ไขคุณสมบัติของคลาส
class LowercaseMeta(type): def __new__(mcs, name, bases, attrs): lower_attrs = {} for k, v in attrs.items(): if not k.startswith('__'): lower_attrs[k.lower()] = v else: lower_attrs[k] = v return type.__new__(mcs, name, bases, lower_attrs) class LowercaseClass(metaclass=LowercaseMeta): BAR = True def HELLO(self): print('hello') print(dir(LowercaseClass)) LowercaseClass().hello()
ผลลัพธ์
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'hello'] hello
ตัวอย่าง 2 − เพิ่ม attribute เพิ่มเติมให้คลาส
class ListMeta(type): def __new__(mcs, name, bases, attrs): attrs['add'] = lambda self, value: self.append(value) return type.__new__(mcs, name, bases, attrs) class MyList(list, metaclass=ListMeta): pass l = MyList() l.add(1) print(l) def class_decorator(cls): cls.add = lambda self, value: self.append(value) return cls @class_decorator class MyList(list): pass l = MyList() l.append(1) print(l)
ผลลัพธ์
[1] [1]
Attribute __metaclass__
ใน Python ไม่ว่าจะมีคลาสหรือหนึ่งใน bases ของมันมี attribute __metaclass__ มันจะถูกนำมาเป็น metaclass ไม่เช่นนั้น type คือ metaclass เราสามารถมี attribute __metaclass__ เมื่อเราเขียนคลาสแบบ −
เกิดอะไรขึ้นเมื่อเรากำหนด คลาสแบบ −
class hello(object): x = 10
ในข้างต้น hello class ไม่มี attribute __metaclass__ ดังนั้น type ถูกใช้แทน และการสร้างคลาสทำได้ดังนี้ −
hello = type(name, bases, dict)
ในกรณี hello ของเรามี metaclass กำหนด −
class hello(object): __metaclass__ = myMetaClass pass
ตอนนี้ในตัวอย่างข้างต้น การสร้างคลาสทำโดยใช้ myMetaClass แทน type Hello = myMetaClass(name, bases, dict)