Python的元编程案例
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.什么是元编程
元编程概念来自LISP和smalltalk。
我们写程序是直接写代码,是否能够用代码来生成未来我们需要的代码吗?这就是元编程。
例如,我们写一个类class A,能否用代码生成一个类出来?
用来生成代码的程序称为元程序metaprogram,编写这种程序就称为元编程metaprogramming。
Python语言能够通过反射实现元编程。
Python中所有非object类都继承自object类 所有类的类型包括type类都是type type类继承自object类,object类的类型也是type类
二.type类
1>.查看type的构造方法
2>.使用type构造一个新类型(可以借助type构造任何类,用代码来生成代码,这就是元编程)
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 def __init__(self,name,age): 7 self.name = name 8 self.age = age 9 10 def show(self): 11 print(self.__dict__) 12 13 student = type("Student",(object,),{"school_address":"北京","__init__":__init__,"show":show}) 14 15 print(student) 16 print(student.__dict__) 17 print(student.__base__) 18 print(student.mro()) 19 20 student("jason",18).show()
<class '__main__.Student'> {'school_address': '北京', '__init__': <function __init__ at 0x1006a2e18>, 'show': <function show at 0x10215fae8>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None} <class 'object'> [<class '__main__.Student'>, <class 'object'>] {'name': 'jason', 'age': 18}
三.使用type构建元类
1>.参考案例
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 #一个类可以继承自type类。注意不是继承自object类了。只要元类是ModelMeta,创建类对象时,就会调用ModelMeta的__new__方法 7 class ModelMeta(type): 8 def __new__(cls, name,bases,dict): 9 print(name) 10 print(bases) 11 print(dict,"======") 12 return super().__new__(cls,name,bases,dict) 13 14 #继承自type,ModelMeta就是元类,它可以创建出其它类。 15 class A(metaclass=ModelMeta): 16 id = 1000 17 def __init__(self): 18 print("A.__init__") 19 20 print("{0} 1 我是分割线 {0}".format("*" * 15)) 21 22 #第二种 B继承自A后,依然是从ModelMeta的类型 23 class B(A): 24 def __init__(self): 25 print("B.__init__") 26 27 print("{0} 2 我是分割线 {0}".format("*" * 15)) 28 #第三种 元类就可以使用下面的方式创建新的类 29 p = ModelMeta("Person",(B,),{}) 30 31 #D、E是type的实例 32 class D:pass #等效于 D = type("D",(),{}) 33 E = type("E",(),{}) 34 35 #F是元类 36 class F(ModelMeta):pass 37 38 print("{0} 3 我是分割线 {0}".format("*" * 15)) 39 40 print(type(A),A.__bases__) 41 print(type(B),B.__bases__) 42 print(type(p),p.__bases__) 43 44 print("{0} 4 我是分割线 {0}".format("*" * 15)) 45 print(type(D),D.__bases__) 46 print(type(E),E.__bases__) 47 print(type(F),F.__bases__)
A () {'__module__': '__main__', '__qualname__': 'A', 'id': 1000, '__init__': <function A.__init__ at 0x10195fae8>} ====== *************** 1 我是分割线 *************** B (<class '__main__.A'>,) {'__module__': '__main__', '__qualname__': 'B', '__init__': <function B.__init__ at 0x10195fb70>} ====== *************** 2 我是分割线 *************** Person (<class '__main__.B'>,) {} ====== *************** 3 我是分割线 *************** <class '__main__.ModelMeta'> (<class 'object'>,) <class '__main__.ModelMeta'> (<class '__main__.A'>,) <class '__main__.ModelMeta'> (<class '__main__.B'>,) *************** 4 我是分割线 *************** <class 'type'> (<class 'object'>,) <class 'type'> (<class 'object'>,) <class 'type'> (<class '__main__.ModelMeta'>,)
2>. 元类的应用
1 class Field: 2 def __init__(self, fieldname=None, pk=False, null=False): 3 self.fieldname = fieldname 4 self.pk = pk 5 self.null = null 6 7 def __repr__(self): 8 return "<Field {} {} {}>".format( 9 self.fieldname, 10 self.pk, 11 self.null 12 ) 13 14 class ModelMeta(type): 15 def __new__(cls, name, bases, attrs:dict): 16 print('M ~~~~~~~~') 17 print(cls) 18 print(name, bases, attrs) 19 if not hasattr(attrs, 'db_table'): 20 attrs['db_table'] = name.lower() 21 primarykeys = [] 22 for k, v in attrs.items(): 23 if isinstance(v, Field): 24 if not v.fieldname or v.fieldname.strip() == '': 25 v.fieldname = k # 字段没有名字使用属性名 if v.pk: 26 primarykeys.append(v) 27 attrs['__primarykeys__'] = primarykeys 28 return super().__new__(cls, name, bases, attrs) 29 30 class Model(metaclass=ModelMeta): 31 """从Model继承的类的类型都是ModelMeta""" 32 33 34 class Student(Model): 35 id = Field(pk=True, null=False) 36 name = Field('username', null=False) 37 age = Field() 38 39 print("{0} 我是分割线 {0}".format("*" * 15)) 40 print(Student.__dict__)
M ~~~~~~~~ <class '__main__.ModelMeta'> Model () {'__module__': '__main__', '__qualname__': 'Model', '__doc__': '从Model继承的类的类型都是ModelMeta'} M ~~~~~~~~ <class '__main__.ModelMeta'> Student (<class '__main__.Model'>,) {'__module__': '__main__', '__qualname__': 'Student', 'id': <Field None True False>, 'name': <Field username False False>, 'age': <Field None False False>} *************** 我是分割线 *************** {'__module__': '__main__', 'id': <Field id True False>, 'name': <Field username False False>, 'age': <Field age False False>, 'db_table': 'student', '__primarykeys__': [<Field id True False>, <Field age False False>], '__doc__': None}
四.元编程总结
元类是制造类的工厂,是用来构造类的类。 构造好元类,就可以在类定义时,使用关键字参数metaclass指定元类,可以使用最原始的 metatype(name, bases, dict)的方式构造一个类。
元类的 __new__() 方法中,可以获取元类信息、当前类、基类、类属性字典。
元编程一般用于框架开发中。
开发中除非你明确的知道自己在干什么,否则不要随便使用元编程 99%的情况下用不到元类,可能有些程序员一辈子都不会使用元类 Django、SQLAlchemy使用了元类,让我们使用起来很方便。