• Python-元编程


    1、元编程:

      元编程 概念来自 LISP 和 smalltalk

      我们写程序 是直接写代码,是否能够用代码来生成未来我们需要的代码,这就是元编程。

      用阿里生成代码的程序称为元程序,metaprogram,编写这种程序就称为元编程。

      Python 语言能够通过反射实现 元编程

      

      python 中;

        所有非object 类都继承自object 类

        所有类的类型包括 type类 都是type

        type类 继承自object 类,object类的类型也是type类

    2、type类

      type构建类: 

    1 class type(object):
    2     """
    3     type(object_or_name, bases, dict)
    4     type(object) -> the object's type  ----> 返回对象的类型,例如 type(10)
    5     type(name, bases, dict) -> a new type ----> 返回一个新的类型
    6     """

      测试:

    1 XClass = type('mycalss', (object,), {'a':100, 'b':'string'})
    2 
    3 print(XClass)
    4 print(XClass.__dict__)
    5 print(XClass.__name__)
    6 print(XClass.__bases__)
    7 print(XClass.mro())

      结果:

    <class '__main__.mycalss'>
    {'a': 100, 'b': 'string', '__module__': '__main__', '__dict__': <attribute '__dict__' of 'mycalss' objects>, '__weakref__': <attribute '__weakref__' of 'mycalss' objects>, '__doc__': None}
    mycalss
    (<class 'object'>,)
    [<class '__main__.mycalss'>, <class 'object'>]

       mycalss 是创建类的 标识符

      (objects,): 基类

      类似命名元组

      

      测试:

     1 def __init__(self):
     2     self.x = 100
     3 
     4 def show(self):
     5     print(self.__dict__)
     6     print(self.x)
     7 
     8 XClass = type('myclass', (object,), {'a':100,'b':111, 'show':show, '__init__':__init__})
     9 
    10 print(XClass)
    11 print(XClass.__name__)
    12 print(XClass.__dict__)
    13 print(XClass.mro())
    14 
    15 print('-' * 40)
    16 XClass().show()

      结果:

    1 <class '__main__.myclass'>
    2 myclass
    3 {'a': 100, 'b': 111, 'show': <function show at 0x00000000023322F0>, '__init__': <function __init__ at 0x00000000004BC1E0>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'myclass' objects>, '__weakref__': <attribute '__weakref__' of 'myclass' objects>, '__doc__': None}
    4 [<class '__main__.myclass'>, <class 'object'>]
    5 ----------------------------------------
    6 {'x': 100}
    7 100

      可以借助type 构造 任何类,用代码来生成代码,这就是元 编程

    3、构造元类:

      一个类可以继承自type 类,注意不是继承自 object 类了。

     1 class ModelMeta(type):
     2     def __new__(cls, *args, **kwargs):
     3         print(cls)
     4         print(args) # 就是 type(name,bases, dict)的参数
     5         print(kwargs)
     6         print('------------------------------')
     7         return super().__new__(cls, *args, **kwargs)
     8 # 此处的 ModelMeta 就是元类,继承自type,它可以创建出其他类
     9 
    10 # 第一种 使用metaclass 关键字 参数指定元类
    11 class A(metaclass=ModelMeta):
    12     id = 100
    13 
    14     def __init__(self):
    15         print(' ==== A ====')
    16 print(A.__class__)
    17 print(A.mro())
    18 print('~~~~~~~~~~~~~~====~~~~~~~~~~')
    19 # 第二种 B继承自 A 后,依然是从ModelMeata的类型
    20 class B(A):
    21     def __init__(self):
    22         print('==== B ====')
    23 
    24 print(B.__class__)
    25 print(B.mro())
    26 print('~~~~~~~~~~~~====~~~~~~~~~~~~')
    27 # 第三种 元类就可以使用下面的方式创建新的类
    28 C = ModelMeta('C', (), {})
    29 print(C.__class__)
    30 print(C.mro())
    31 print('~~~~~~~~~~~~====~~~~~~~~~~~~')
    32 
    33 # D,E 是type的 实例, 没有使用自定义的元类,所以默认使用type
    34 class D:pass
    35 E = type('E', (), {})
    36 
    37 class F(ModelMeta):pass # 和A  不一样,没有使用关键字 metaclass
    38 
    39 print('=============================')
    40 print(type(A), A.__bases__)
    41 print(type(B), B.__bases__)
    42 print(type(C))
    43 print(type(D))
    44 print(type(E))
    45 print(type(F), F.__bases__)

      结果:

     1 D:python3.7python.exe E:/code_pycharm/test_in_class/tt14.py
     2 <class '__main__.ModelMeta'>
     3 ('A', (), {'__module__': '__main__', '__qualname__': 'A', 'id': 100, '__init__': <function A.__init__ at 0x00000000029422F0>})
     4 {}
     5 ------------------------------
     6 <class '__main__.ModelMeta'>
     7 [<class '__main__.A'>, <class 'object'>]
     8 ~~~~~~~~~~~~~~====~~~~~~~~~~
     9 <class '__main__.ModelMeta'>
    10 ('B', (<class '__main__.A'>,), {'__module__': '__main__', '__qualname__': 'B', '__init__': <function B.__init__ at 0x0000000002942378>})
    11 {}
    12 ------------------------------
    13 <class '__main__.ModelMeta'>
    14 [<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
    15 ~~~~~~~~~~~~====~~~~~~~~~~~~
    16 <class '__main__.ModelMeta'>
    17 ('C', (), {})
    18 {}
    19 ------------------------------
    20 <class '__main__.ModelMeta'>
    21 [<class '__main__.C'>, <class 'object'>]
    22 ~~~~~~~~~~~~====~~~~~~~~~~~~
    23 =============================
    24 <class '__main__.ModelMeta'> (<class 'object'>,)
    25 <class '__main__.ModelMeta'> (<class '__main__.A'>,)
    26 <class '__main__.ModelMeta'>
    27 <class 'type'>
    28 <class 'type'>
    29 <class 'type'> (<class '__main__.ModelMeta'>,)
    30 
    31 Process finished with exit code 0

      修改代码如下:

     1 class ModelMeta(type):
     2     def __new__(cls, name, bases, dict):
     3         print(cls)
     4         print(name)
     5         print(dict)
     6         print('------------------------------')
     7         return super().__new__(cls, name, bases, dict)
     8 # 此处的 ModelMeta 就是元类,继承自type,它可以创建出其他类
     9 
    10 # 第一种 使用metaclass 关键字 参数指定元类
    11 class A(metaclass=ModelMeta):
    12     id = 100
    13 
    14     def __init__(self):
    15         print(' ==== A ====')

       从结果看出,只要元类是ModelMeta,创建类对象时,就会调用MoelMeta的 __new__方法

    元类的应用:

      模拟创建表格式

     1 class Field:# 定义字段的属性类
     2     def __init__(self, fieldname=None,pk=False, nullable=True):
     3         self.fieldname= fieldname
     4         self.pk = pk
     5         self.nullable = nullable
     6 
     7     def __repr__(self):
     8         return '<Field {}'.format(self.fieldname)
     9 
    10 class ModelMeta(type):
    11     def __new__(cls, name, bases, attrs:dict):
    12         print(cls)
    13         print(name)
    14         print(bases)
    15         print('=====', attrs,'=====')
    16 
    17         if '__tablename__' not in attrs.keys():
    18             attrs['__tablename__'] = name
    19 
    20         primarykey = []
    21         for k, v in attrs.items():
    22             if isinstance(v, Field):
    23                 if v.fieldname is None:
    24                     v.fieldname = k
    25                 if v.pk:
    26                     primarykey.append(v)
    27         attrs['__primarykey__'] = primarykey
    28 
    29         return super().__new__(cls, name, bases, attrs)
    30 
    31 class ModelBase(metaclass=ModelMeta):
    32     ''' 从 ModelBases 继承的类的类型都是ModelMeta '''
    33     pass
    34 
    35 class Students(ModelBase):
    36     id = Field(pk=True, nullable = False)
    37     name = Field('username', nullable=False)
    38     age = Field()
    39 
    40 print('====================================')
    41 print(Students.__dict__)

      结果:

     1 D:python3.7python.exe E:/code_pycharm/test_in_class/tt14.py
     2 <class '__main__.ModelMeta'>
     3 ModelBase
     4 ()
     5 ===== {'__module__': '__main__', '__qualname__': 'ModelBase', '__doc__': ' 从 ModelBases 继承的类的类型都是ModelMeta '} =====
     6 <class '__main__.ModelMeta'>
     7 Students
     8 (<class '__main__.ModelBase'>,)
     9 ===== {'__module__': '__main__', '__qualname__': 'Students', 'id': <Field None, 'name': <Field username, 'age': <Field None} =====
    10 ====================================
    11 {'__module__': '__main__', 'id': <Field id, 'name': <Field username, 'age': <Field age, '__tablename__': 'Students', '__primarykey__': [<Field id], '__doc__': None}
    12 
    13 Process finished with exit code 0
    View Code

    元编程总结:

      元类是制造类的工厂,是生成类的类

      构造好元类,就可以在类定义的时候,使用关键字参数 metaclass 指定元类,可以使用最原始的metatype(name,base,dict)的方式 构造一个类

      元类的__new__()方法中,可以获取元类的信息,当前类,基类,类属性字典

      

      元编程一般用于框架开发中,Django SQLAlchemy 都使用了 元类。

    为什么要坚持,想一想当初!
  • 相关阅读:
    js传url中文参数乱码问题
    非远程重启机器
    c#调用带输出参数的存储过程
    在线测试手机、平板页面
    jquery移除select下所有的option选项
    怎样打开谷歌
    ligerui前端框架API地址
    64位操作系统(Windows 2008 R2 X64)ASP.NET 调用32位Excel,word 出现401 – 未授权: 由于凭据无效,访问被拒绝。
    前端框架
    jquery ligerUI中ligerComboBox 初始值问题
  • 原文地址:https://www.cnblogs.com/JerryZao/p/9938976.html
Copyright © 2020-2023  润新知