1、type()函数

  1. if __name__ == '__main__':
  2. h = hello()
  3. h.hello()
  4. print(type(hello))
  5. print(type(h))
  1. Hello, world.
  2. <class 'type'>
  3. <class '__main__.Hello'>

2、metaclass元类

  1. #metaclass 元类 metaclass允许你创建类或者修改类
  2. class Listmetaclass(type):
  3. def __new__(cls, name,bases,attrs):
  4. attrs['add'] = lambda self,value:self.append(value) #增加了add()方法
  5. return type.__new__(cls,name,bases,attrs)
  6. class MyList(list,metaclass=Listmetaclass):
  7. pass
  8. #__new__()方法接收到的参数依次是:
  9.  
  10. #1、当前准备创建的类的对象;
  11. #2、类的名字;
  12. #3、类继承的父类集合;
  13. #4、类的方法集合。
  14.  
  15. #元类一般情况不常用,但总会遇到需要通过metaclass修改类定义的。ORM就是一个典型的例子。
  16. #ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,
  17. # 也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。
  18. #要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。  

  

  1.  

3、精简ORM框架

  1. #开始编写ORM框架
  2. class Field(object):
  3. def __init__(self,name,column_type):
  4. self.name = name
  5. self.column_type = column_type
  6. def __str__(self):
  7. return '<%s:%s>'%(self.__class__.__name__,self.name)
  8.  
  9. class StringField(Field):
  10. def __init__(self,name):
  11. super(StringField,self).__init__(name,'varchar(100)')
  12.  
  13. class IntegerField(Field):
  14. def __init__(self,name):
  15. super(IntegerField,self).__init__(name,'bigint')
  16. #下一步,就是编写最复杂的ModelMetaclass了:
  17. class ModelMetaclass(type):
  18. def __new__(cls, name,bases,attrs):
  19. if name == 'Model': #排除掉对Model类的修改;
  20. return type.__new__(cls,name,bases,attrs)
  21. print('Found Model: %s'%name)
  22. mappings = dict()
  23. for k,v in attrs.items(): #查找定义的类的所有属性,
  24. if isinstance(v,Field): #如果找到一个Field属性,
  25. print('Found mapping: %s ==> %s' % (k, v))
  26. mappings[k] = v #就把它保存到一个__mappings__的dict中
  27. for k in mappings.keys():
  28. attrs.pop(k) #同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性);
  29. attrs['__mappings__'] = mappings # 保存属性和列的映射关系
  30. attrs['__table__'] = name # 假设表名和类名一致 把表名保存到__table__中
  31. return type.__new__(cls,name,bases,attrs)
  32.  
  33. #基类Model
  34. class Model(dict,metaclass=ModelMetaclass):
  35. def __init__(self,**kw):
  36. super(Model,self).__init__(**kw)
  37. def __getattr__(self, item): #没有找到的属性,就在这里找
  38. try:
  39. return self[item]
  40. except KeyError:
  41. raise AttributeError(r"'Model' object has no attrs :'%s'"%item)
  42.  
  43. def __setattr__(self, key, value):
  44. self[key] = value
  45.  
  46. def save(self):
  47. fields = []
  48. params = []
  49. args = []
  50. for k,v in self.__mappings__.items():
  51. fields.append(v.name)
  52. params.append('?')
  53. args.append(getattr(self,k,None))
  54. sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
  55. print('SQL: %s' % sql)
  56. print('ARGS: %s' % str(args))
  57.  
  58. #子类User
  59. # 定义类的属性到列的映射:
  60. class User(Model):
  61. id = IntegerField('id')
  62. name = StringField('username')
  63. email = StringField('email')
  64. password = StringField('password')
  65. age = IntegerField('age')
  66.  
  67. #开始编写ORM框架
    class Field(object):
        def __init__(self,name,column_type):
            self.name = name
            self.column_type = column_type
        def __str__(self):
            return '<%s:%s>'%(self.__class__.__name__,self.name)
  68.  
  69. class StringField(Field):
        def __init__(self,name):
            super(StringField,self).__init__(name,'varchar(100)')
  70.  
  71. class IntegerField(Field):
        def __init__(self,name):
            super(IntegerField,self).__init__(name,'bigint')
    #下一步,就是编写最复杂的ModelMetaclass了:
    class ModelMetaclass(type):
        def __new__(cls, name,bases,attrs):
            if name == 'Model':  #排除掉对Model类的修改;
                return type.__new__(cls,name,bases,attrs)
            print('Found Model: %s'%name)
            mappings = dict()
            for k,v in attrs.items(): #查找定义的类的所有属性,
                if isinstance(v,Field): #如果找到一个Field属性,
                    print('Found mapping: %s ==> %s' % (k, v))
                    mappings[k] =#就把它保存到一个__mappings__的dict中
            for k in mappings.keys():
                attrs.pop(k)  #同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性);
            attrs['__mappings__'] = mappings # 保存属性和列的映射关系
            attrs['__table__'] = name  # 假设表名和类名一致  把表名保存到__table__中
            return type.__new__(cls,name,bases,attrs)
  72.  
  73. #基类Model
    class Model(dict,metaclass=ModelMetaclass):
        def __init__(self,**kw):
            super(Model,self).__init__(**kw)
        def __getattr__(self, item):  #没有找到的属性,就在这里找
            try:
                return self[item]
            except KeyError:
                raise AttributeError(r"'Model' object has no attrs :'%s'"%item)
  74.  
  75.     def __setattr__(self, key, value):
            self[key] = value
  76.  
  77.     def save(self):
            fields = []
            params = []
            args = []
            for k,v in self.__mappings__.items():
                fields.append(v.name)
                params.append('?')
                args.append(getattr(self,k,None))
            sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
            print('SQL: %s' % sql)
            print('ARGS: %s' % str(args))
  78.  
  79. #子类User
    # 定义类的属性到列的映射:
    class User(Model):
        id = IntegerField('id')
        name = StringField('username')
        email = StringField('email')
        password = StringField('password')
        age = IntegerField('age')

 

当用户定义一个class User(Model)时,Python解释器首先在当前类User的定义中查找metaclass,如果没有找到,就继续在父类Model中查找metaclass,找到了,就使用Model中定义的metaclassModelMetaclass来创建User类,也就是说,metaclass可以隐式地继承到子类,但子类自己却感觉不到。

ModelMetaclass中,一共做了几件事情:

  1. 排除掉对Model类的修改;

  2. 在当前类(比如User)中查找定义的类的所有属性,如果找到一个Field属性,就把它保存到一个__mappings__的dict中,同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性);

  3. 把表名保存到__table__中,这里简化为表名默认为类名。

Model类中,就可以定义各种操作数据库的方法,比如save()delete()find()update等等。

我们实现了save()方法,把一个实例保存到数据库中。因为有表名,属性到字段的映射和属性值的集合,就可以构造出INSERT语句。

编写代码试试:

 
  1. if __name__ == '__main__':
  2. u = User(id = 12345,name = 'john',email = '123456789@qq.com',password = '666666')
  3. u.age = 12
  4. u.save()
  1. Found Model: User
  2. Found mapping: id ==> <IntegerField:id>
  3. Found mapping: name ==> <StringField:username>
  4. Found mapping: email ==> <StringField:email>
  5. Found mapping: password ==> <StringField:password>
  6. Found mapping: age ==> <IntegerField:age>
  7. SQL: insert into User (id,username,email,password,age) values (?,?,?,?,?)
  8. ARGS: [12345, 'john', '123456789@qq.com', '666666', 12]

 

即User类中做好了到列的映射的类属性,都能添加到sql语句中,而未做好了到列的映射的类属性:如height,则会过滤掉,实现数据库列的字段的高度可定制

即使在初始化的时候传进了height参数,依然会被过滤掉,而定义好了到列的映射的类属性age,即使没有赋值,也会被默认为None,并添加到数据库中。
 
注:可以看到,save()方法已经打印出了可执行的SQL语句,以及参数列表,只需要真正连接到数据库,执行该SQL语句,就可以完成真正的功能。下面入库操作,还有剩下的删改查操作可自行解决。

python——type()、metaclass元类和精简ORM框架的更多相关文章

  1. Python元类实战,通过元类实现数据库ORM框架

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第19篇文章,我们一起来用元类实现一个简易的ORM数据库框架. 本文主要是受到了廖雪峰老师Python3入门教程的启 ...

  2. [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式

    使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...

  3. 深刻理解Python中的元类(metaclass)以及元类实现单例模式

    在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...

  4. Python中的元类(metaclass)

    推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...

  5. Python面向对象06 /元类type、反射、函数与类的区别、特殊的双下方法

    Python面向对象06 /元类type.反射.函数与类的区别.特殊的双下方法 目录 Python面向对象06 /元类type.反射.函数与类的区别.特殊的双下方法 1. 元类type 2. 反射 3 ...

  6. python基础——使用元类

    python基础——使用元类 type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello. ...

  7. Python 中的元类到底是什么?这篇恐怕是最清楚的了

    类作为对象 在理解元类之前,您需要掌握 Python 的类.Python 从 Smalltalk 语言中借用了一个非常特殊的类概念. 在大多数语言中,类只是描述如何产生对象的代码段.在 Python ...

  8. Python基础:元类

    一.概述 二.经典阐述 三.核心总结 1.类的创建过程 2.元类的使用惯例 四.简单案例 1.默认行为 2.使用元类 五.实践为王 一.概述 Python虽然是多范式的编程语言,但它的数据模型却是 纯 ...

  9. python中面向对象元类的自定义用法

    面向对象中的常用方法 1.instance 和 issubclass instance :判断两个对象是不是一类 issubclass :判断某个类是不是另一个类的子类 #两个常用方法的使用 clas ...

随机推荐

  1. pairwork(黄敬博12061156和黄伟龙12061172)

    结对编程: 结对编程的优缺点: 优点: 1.相互督促,共同为了完成目标而努力: 2.节省时间,通过将疑难问题分开解决,共同讨论,实现了更高效的时间利用率: 3.能力互补,提高代码的质量,同时也提高了测 ...

  2. 我是IT小小鸟读后感

    <我是一只IT小小鸟>一只是我想读list中一个本,但是上次去当当买的时候,竟然缺货了...昨天监考,实在无聊,就上网看电子书了,一天就看完了,看得有点仓促,所以理解估计不深. 1.刘帅: ...

  3. CAS (1) —— Mac下配置CAS到Tomcat(服务端)

    CAS (1) -- Mac下配置CAS到Tomcat(服务端) tomcat版本: tomcat-8.0.29 jdk版本: jdk1.8.0_65 cas版本: cas4.1.2 cas-clie ...

  4. <构建之法>第一二三章感悟

    第一章: 看了大概了解软件从一个想法到最终成品的一个过程.软件先是由一个想法引出的,有那个想法,你需要一个工具去做什么,根据自己想要的功能大概做一个能实现基本功能的软件,对客户提出的要求进行完善,实现 ...

  5. “四则运算生成程序——GUI支持和部分功能改进”链接

    项目成员:张金生     张政 <正文随笔发布在张金生博客中> 四则运算生成程序——GUI支持和部分功能改进

  6. 关于mysqlbinlog的重要性.

    今天在做update更新数据的时候,因为没有统一好需要更新的数据编执行了update操作,所以需要回滚到先前的数据,所以就赶紧去服务器看binlog日志,结果一看binlog竟然没有开启,把我给惊的啊 ...

  7. poj 2299 Ultra-QuickSort(树状数组求逆序数)

    链接:http://poj.org/problem?id=2299 题意:给出n个数,求将这n个数从小到大排序,求使用快排的需要交换的次数. 分析:由快排的性质很容易发现,只需要求每个数的逆序数累加起 ...

  8. 一文总结之Redis

    目录 Redis 目标 Redis简介 什么是Redis 特性 Redis当前应用情况 安装 基本使用 键 exists判断键存在性.del删除键.type键类型 expire key的时效性设置 基 ...

  9. 【HLSDK系列】groupinfo的基本用法

    如果你经常写AMXX,你应该会知道有个 pev->groupinfo 变量,但我猜大部分人都不会用这个变量,这个变量涉及很多实体处理功能,下面列举几个最常用的. ① 玩家与非玩家实体之间的碰撞检 ...

  10. 5W2H方法

    5W2H分析方法也叫七问分析法,是二战中美国陆军兵器修理部首创.简单.方便.易于理解.使用,富有启发意义,被广泛应用于企业管理和技术活动,对于决策和执行性的措施也非常有帮助,有助于弥补考虑问题的疏漏 ...