python入门学习记录之元类type和metaclass的使用

引言:众所周知 python是解释型语言,亦是动态语言,解释型语言和编译型语言的不同在于函数和类的定义是在运行时创建的。

例如有一个user.py和class user(object):,python解释器就会在载入该user.py模块时依次执行,动态创建user类对象

一:python有一个type()函数:该函数的作用可以查看一个类型或变量的类型

type(user):type class类型

type(user):class-user类型

type()函数既可以返回一个数的类型。还可以运行时动态创建类,其实user实例在创建时也是由type()创建的,解析器扫描到user需创建实例便调用type函数进行创建,同样的,我们不需要提前写好类的定义也能在运行时动态创建,这就是动态语言的魅力。

type(name,tuple,fn)创建类有三个参数:

1:要创建的类名

2:要创建的类需继承的元祖,单继承需加,

3:需绑定的函数:例def fun():hello = fun(为类绑定一个hello函数)

现在我们便可使用该类了

例:

User = type('User',(object,),hello=fn)

user=User()

user.hello()

正常情况下我们都是用class xx():定义,type()函数可以创建类便说明动态语言本身支持运行时创建类

动态语言和静态语言的不同在于,静态语言需定义好要运行的类,再由编译器编译成字节码文件再交由机器执行

动态语言则省去了编译这部分,直接在运行时由解释器来解析数据交由机器执行

二:元类metaclass的使用

除了使用type()创建类时,我们还可以使用metaclass控制类的创建行为:

metaclass直译为元类,也称为python的魔术代码

当我们定义好类之后,可以通过metaclass创建类的实例,先定义类,再定义metaclass,再创建实例

如果想先创建类,就先定义metaclass,再创建class,再创建实例

metaclass允许你创建类和修改类,所以可以把类看成是metaclass创建出来的实例

创建metaclass,类名结尾一般为Metaclass,Metaclass是类的模板,所以需继承type

例:class ListMetaclass(type):

其中__now__有4个重要参数:

cls:准备创建的类的对象,

name:类名

base:类继承的父类(list)

attrs:类的函数集合

    class ListMetaclass(type):
    def  __now__(cls,name,base,attrs):

    attrs['hello'] = lambda self,value:self.append(value)

    return type.__now__(cls,name,base,attrs)

    class Mylist(List,metaclass=ListMetaclass)

        pass

加上metaclass=,其中Mylist 拥有hello这个函数,需传一个value ,等价于定义了def hello(self,value):

而继承的List却是没有hello函数的,因为是创建在metaclass的实例Mylist上的

metaclass就相当于java的aop,aop的原理是java代理技术,在运行时由代理子类来替换父类执行

metaclass也是在类运行时增加函数方法的行为,还可以修改类的函数方法,aop不可以

metaclass的应用场景不是非常多,可以简单时尽量也不要使用metaclass

例如ORM就是一个典型的例子:
orm全称为对象关系-映射,将类的对象在运行时映射为数据库的表字段,也就是一个类的字段对应一个表的字段

要编写orm框架,所有的类只能动态定义,在运行时由使用者来构造类:

#!/usr/bin/env python
# -*- encoding:utf-8 -*-
"""

# !/user/bin/env python
# ! -*- coding:utf-8 -*-
'''
我们想要的结果是
user = User('1','zf','100.0')
user.save()#保存到mysql
or:
user.update_user()#修改id为1的数据
'''
if __name__ == '__main__':
    # type create hello_class
    # args1:要动态创建的class的名称
    # args2:要动态创建的class的父类继承,使用tuple表示,单继承加,
    # args3:要动态创建的class的函数绑定,dict(函数名=已创建函数名,fn=fn)
    # h1 = type(args1,args2,args3)

    # 写一个ORM映射框架,一行sql对应着对象的每个字段
    # 定义一个字段基类
    class Field(object):
        def __init__(self, field_name):
            self.field_name = field_name

        def __str__(self):
            print('nam=%s,type=%s' % (self.field_name))


    # 定义一个数据类型表,以下示例简短为只有三种Str,Int,Float
    # str
    class str_Field(Field):
        def __init__(self, field_name):
            super(str_Field, self).__init__(field_name)


    # int
    class int_Field(Field):
        def __init__(self, field_name):
            super(int_Field, self).__init__(field_name)


    # float
    class float_Field(Field):
        def __init__(self, field_name):
            super(float_Field, self).__init__(field_name)


    # 定义metaclass
    class ModelMetaclass(type):
        # 类对象,类名,继承类的父类集合,方法集合
        def __new__(cls, name, base_cls, attrs):
            if name == 'Model':
                return type.__new__(cls, name, base_cls, attrs)
            mappings = dict()  # 空字典

            for func_name, func_type in attrs.items():
                if isinstance(func_type, Field):
                    mappings[func_name] = func_type

            for key in mappings.keys():
                attrs.pop(key)

            attrs['mappings'] = mappings
            attrs['table_name'] = name
            return type.__new__(cls, name, base_cls, attrs)


    class Model(dict, metaclass=ModelMetaclass):
        def __init__(self, **kwargs):
            # 调用dict的父类init
            super(Model, self).__init__(kwargs)

        def __getattr__(self, item):
            return self[item]

        def __setattr__(self, key, value):
            self[key] = value

        # 数据库增加操作
        def save(self):
            fields = []
            args = []
            values = []
            table_name = self.table_name
            for k, v in self.mappings.items():
                fields.append(v.field_name)
                args.append(getattr(self, v.field_name, None))
                values.append('?')
            SQL = 'insert into %s(%s) values (%s)' % (table_name, ','.join(fields), ','.join(values))
            print('SQL: %s 运行' % SQL)
            print('参数列表args:%s' % args)

        def update_user(self, **kwargs):
            if kwargs: super(Model, self).__init__(kwargs)
            fields = []
            args = []
            values = []
            table_name = self.table_name

            for k, v in self.mappings.items():
                fields.append(v.field_name)
                args.append(getattr(self, v.field_name, None))
                values.append('?')
            #合并field值

            dicts_user = dict(zip(fields, values))
            SQL ='update %s set name=%s ,salary=%s where id = %s' %(table_name,dicts_user['name'],dicts_user['salary'],dicts_user['id'])
            print('SQL:%s 运行' %SQL)
            print('参数列表args:%s ' %args)
    # user entity
    class User(Model):

        id = int_Field('id')  # 编号
        name = str_Field('name')  # 姓名
        salary = float_Field('salary')  # 薪水

        def __init__(self, **kwargs):
            if kwargs:
                try:

                    kwargs1 = {'id': kwargs['id'], 'name': kwargs['name'], 'salary': kwargs['salary']}
                    super(User, self).__init__(**kwargs1)
                except:
                    raise

    #修改,可以不传参数,可以在初始化时传完
    user = User()
    user.update_user(id=123,name=234,salary=345)
    user.save()


















增加和修改的运行结果:

结尾:这样一个精简的ORM实例就完成了,metaclass还是很强大的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章