看完必会元编程
元編程
元編程的概念來自LISP和smalltalk。
用來生成代碼的程序稱為元程序metaprogram,編寫這種程序就稱為元編程metaprogramming。
python主要通過反射來實現元編程。
Python中
所有非object類都繼承自Object類
所有類的類型包括type類都是type
type類繼承自object類,object類的類型也是type類
type類
type構建類
class type(object):def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__"""type(object_or_name, bases, dict)type(object) -> the object's type type(name, bases, dict) -> a new type# (copied from class doc)"""pass構建
def __init__(self):self.x = 1000def show(self):return self.__dict__XClass = type('myclass', (object,), {'a':100, 'b': 'string', 'show':show, '__init__':__init__}) # 字典是類屬性 print(XClass) print(XClass) print(XClass.__name__) print(XClass.__dict__) print(XClass.mro())XClass().show()可以借助type構造任何類,用代碼生成代碼,這就是元編程。
構建元類
一個類可以繼承自type類
class ModelMeta(type):def __new__(cls, *args):print(cls)print(*args)return super().__new__(cls, *args)繼承自type,ModelMeta就是元類,它可以創建出其他類。
class ModelMeta(type): # 繼承自typedef __new__(cls, name, bases, attrs: dict):print(cls)print(name)print(bases)print(attrs)print("--------")return super().__new__(cls, name, bases, attrs)# 第一種 使用metaclass關鍵字參數指定元類 class A(metaclass=ModelMeta):id = 100def __init__(self):self.x = 2000# 第二種 B繼承自A后,依然是從ModelMeta的類型 class B(A): # 繼承pass# 第三種 元類就可以使用下面的方式創建新的類 C = ModelMeta('Class', (), {'y': 200})print(type(A)) print(type(B)) print(type(C))從運行結果還可以分析出__new__(cls, *args) 的參數結構
中間是一個元組 ('A', (), {'__init__': <function A.__init__ at 0x0000000000B6E598>, '__module__':'__main__', '__qualname__': 'A', 'id': 100})
對應 (name, bases, dict)
從運行結果可以看出,只要元類是ModelMeta,創建類對象時,就會調用ModelMeta的__new__方法
元類的應用
class Field:def __init__(self, fieldname=None, pk=False, nullable=False):self.fieldname = fieldnameself.pk = pkself.nullable = nullabledef __repr__(self):return "<Field {}>".format(self.fieldname)class ModelMeta(type): # 繼承自typedef __new__(cls, name, bases, attrs: dict):print(cls)print(name)print(bases)print(attrs, '-------------')# 使用元類動態注入表名tblname = '__tablename__'if tblname not in attrs.keys():attrs[tblname] = nameprimarykeys = []for k, v in attrs.items():if isinstance(v, Field):print(k)print(v)print(v.fieldname)if v.fieldname is None:v.fieldname = k # 沒有名字則使用屬性名if v.pk:primarykeys.append(v)attrs['__primarykeys__'] = primarykeysreturn super().__new__(cls, name, bases, attrs)class ModelBase(metaclass=ModelMeta):passclass Student(ModelBase):id = Field(pk=True, nullable=False)name = Field('username', nullable=False)age = Field()print('----------------') print(Student.__dict__)元編程的總結
元類是制造類的工廠,是生成類的類。
構造好元類,就可以在類定義時,使用關鍵字參數metaclass指定元類,可以使用最原始的metatype(name,
bases, dict)的方式構造一個類。
元類的 __new__()方法中,可以獲取元類信息、當前類、基類、類屬性字典。
元編程一般用于框架開發中。
總結
- 上一篇: 理解Base64编码及实现编解码Base
- 下一篇: 22.Odoo产品分析 (三) – 人力