元编程 什么是元编程? 用代码来生成代码,或者说,用程序来生成程序,就叫元编程。Python能通过反射实现元编程。
什么是元类? 与元编程相关的一个概念是元类。什么是元类呢,具体到Python,用来创建类的类,就叫元类 。元类是制造类的工厂。
在Python中,一个普通类创建出来的东西是类的实例,实例是一个对象。而元类也是一种类,它创建出来的东西是另一个普通类 ,普通类也是一个对象(Python中一切皆对象),然后这个普通类,又可以创建出类的实例。所以说,元类是类的类。它们的构建过程如下图:
Python中:
1、所有非object类都继承自object类(包括type) 2、所有类的类型都是type(包括type、object、元类) 3、type类继承自object(符合第1句)
虽然type也继承自object,但是我们自己写的类,继承自object与继承自type,会有些不同。
type元类 type这个类,不仅可以获取Python中对象的类型,比如type(123),会告诉你123是int类型(int也是类)。
type也可以作为元类,来构建其他类。语法是:
type(name, bases, dict) -> a new type
返回一个新的类型
其中,name为类的名称,bases为类的继承列表,dict为类的属性字典。比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def __init__ (self) : self.x = 123 NewClass = type('newclass' , (object,), {'a' :100 , 'b' :[], '__init__' :__init__}) print(NewClass.__dict__) class newclass (object) : a = 100 b = [] def __init__ (self) : self.x = 456 print(newclass.__dict__)
以上例子没有什么神奇。元类的真正用途,是在元类的构造方法(__new__, __init__)里写我们的代码,从而改变一个类的构建行为。
上面用type构建了一个新的类,类在程序中是代码,type(…)调用也是代码。所以,这种用代码来生成代码的过程,就是元编程 。
构建自己的元类 如果一个类继承自type(而不是object),它就会成为元类,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class ModelMeta (type) : def __new__ (cls, name, bases, _dict) : print(cls) print(name) print(bases) print(_dict) return super().__new__(cls, name, bases, _dict) class A (metaclass=ModelMeta) : x = 999 def __init__ (self) : print('A.init' ) print('=' * 30 ) class B (A) : def __init__ (self) : print('B.init' ) print('=' * 30 ) C = ModelMeta('C' , (), {'x' :999 }) print('=' * 30 ) class D (ModelMeta) : pass
元类的应用 元编程可用于开发框架。比如ORM(对象关系映射)。将数据库的操作与类(以及实例)的操作联系起来,就可以使用元类。
映射关系:
表 ⟶ class 行 ⟶ 实例 字段 ⟶ 属性(描述器,见 这里 )
一个简单的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 class Field : def __init__ (self, fn=None, tp=None, pk=False, null=True) : self.fn = fn self.tp = tp self.pk = pk self.nl = null self.value = None def __get__ (self, instance, owner) : return self.value def __set__ (self, instance, value) : if self.tp: self.value = self.tp(value) def __delete__ (self, instance) : del self.value class ModelMeta (type) : def __new__ (cls, name, bases, attrs) : if '__tblname__' not in attrs.keys(): attrs['__tblname__' ] = name primarykeys = [] for k,v in attrs.items(): if isinstance(v, Field): if v.fn is None : v.fn = k if v.pk: primarykeys.append(v) v.nl = False attrs['__primarykeys__' ] = primarykeys return type.__new__(cls, name, bases, attrs) class Base (metaclass=ModelMeta) : def __init__ (self, **kwargs) : for k,v in kwargs.items(): if k not in self.__class__.__dict__: raise AttributeError(f"'{k} ' is not a field name" ) setattr(self, k, v) class Student (Base) : sid = Field(tp=int, pk=True ) name = Field('username' , tp=str, null=False ) age = Field(tp=int) def __repr__ (self) : return f"<{self.__class__.__name__} sid={self.sid} name={self.name} age={self.age} >" s = Student(sid=1 ) print(s) print('=' * 30 ) s.name = 123 s.age=20 print(s) print('=' * 30 ) print(s.name, s.age, type(s.name))