python ORM理解、元类
元类
参考链接:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319106919344c4ef8b1e04c48778bb45796e0335839000
1)type()
结论:动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。正常情况下,我们都用 class Xxx... 来定义类,但是, type() 函数也允许我们动态创建出类来,也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。
教程里的 self 代表的是类的实例。补充一下 self.__class__ 则指向类。
参考链接:https://www.cnblogs.com/jessonluo/p/4717140.html
然后作者举了一个例子,用类创建实例的过程引入用什么来创建类的这个问题,答案是用 type() , type() 函数既可以返回一个对象的类型,又可以创建出新的类型,比如,我们可以通过 type() 函数创建出 Hello 类
>>> def fn(self, name='world'): # 先定义函数
... print('Hello, %s.' % name)
...
>>> Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
>>> h = Hello()
>>> h.hello()
Hello, world.
>>> print(type(Hello))
<class 'type'>
>>> print(type(h))
<class '__main__.Hello'>
参数:使用 type() 来创建一个class,依次传入三个参数:class名称;继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;class的方法名称与函数绑定,这里我们把函数 fn 绑定到方法名 hello 上。
通过 type() 函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用 type() 函数创建出class。
2)元类
元类是用来创建类的,他们之间的关系就是类和实例之间的关系,换句话说,你可以把类看成是metaclass创建出来的“实例”。
然后作者举了一个例子,用metaclass来为自定义的myList增加一个add方法
# metaclass是类的模板,所以必须从`type`类型派生:
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):#参数依次是当前准备创建类的对象、类的名称、类继承的父类集合、类的方法集合
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
之后再在自定义类的代码中传入关键字参数mataclass:
class MyList(list, metaclass=ListMetaclass):
pass
当我们传入关键字参数 mataclass 时,魔术方法就生效了,这个参数会指示python解释器在创建这个MyList类时,要通过 ListMetaclass.__new__() 来创建,在上面这个new中,我们就可以修改类的定义。比如,加上新的方法,然后,返回修改后的定义。
最后,作者说了一句乍看起来非常让人不明所以但冷静分析一下还是有道理的话,那就是上面举的例子很智障,因为我们明明可以在MyList定义的代码中假如add方法,但是作者也说了,这是是一个例子而已,是为了让我们明白这个元类可以用来定义类的代码,而总是会有需要用到元类的地方,比如ORM
ORM
但是,总会遇到需要通过metaclass修改类定义的。ORM就是一个典型的例子。
1)作用
补充:
为什么所有的类必须只能动态生成呢,因为这个框架是把数据库中的每一行转化为每一个对象,说的再通俗一点,这个框架会用在很多数据库中,而每个数据库有多个表,而如果每个表都自己定义一个类,那么就失去了框架的通用性,就没有必要了。
ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。为什么呢,一个表定义一个类不就行了,或许这个ORM就是解决这个的,只创建一个类,然后根据表名动态的创建不同的类?
2)创建ORM
ORM是一个类
作者给出了创建ORM的一种方法,就是从使用者的角度,思考你想怎么去使用它,然后再根据接口去定义ORM
class User(Model):
# 定义类的属性到列的映射:
id = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password') # 创建一个实例:
u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')
# 保存到数据库:
u.save()
其中的父类Model、属性类型 StringField 、 IntegerField 是由ORM提供的,剩下的魔术方法比如 save() 全部由 metaclass 自动完成。虽然 metaclass 的编写会比较复杂,但ORM的使用者用起来却异常简单。
首先来定义 Field 类,它负责保存数据库表的字段名和字段类型:
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)
在 Field 的基础上,进一步定义各种类型的 Field ,比如 StringField , IntegerField 等等:
class StringField(Field):
def __init__(self, name):
super(StringField, self).__init__(name, 'varchar(100)')#调用super时,不用传入self class IntegerField(Field):
def __init__(self, name):
super(IntegerField, self).__init__(name, 'bigint')
补充:
super()
参考链接:https://www.runoob.com/python/python-func-super.html
是用于调用父类或者超类的方法
# super(StringField,self) 首先找到 StringField 的父类(就是类 Field),然后把类 StringField 的对象转换为类 Field 的对象,然后再调用Field的__init__方法
最复杂的:就是编写最复杂的 ModelMetaclass 了:
在 ModelMetaclass 中,一共做了几件事情:
排除掉对 Model 类的修改;
在当前类(比如 User )中查找定义的类的所有属性,如果找到一个 Field 属性,就把它保存到一个 __mappings__ 的dict中,同时从类属性中删除该 Field 属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性,但是当删除类属性的时候,访问的将会是类的属性);
把表名保存到 __table__ 中,这里简化为表名默认为类名。
class ModelMetaclass(type): def __new__(cls, name, bases, attrs):
if name=='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):
print('Found mapping: %s ==> %s' % (k, v))
mappings[k] = v
for k in mappings.keys():
attrs.pop(k)
attrs['__mappings__'] = mappings # 保存属性和列的映射关系
attrs['__table__'] = name # 假设表名和类名一致
return type.__new__(cls, name, bases, attrs)
以及基类 Model :
当用户定义一个 class User(Model) 时,Python解释器首先在当前类 User 的定义中查找 metaclass ,如果没有找到,就继续在父类 Model 中查找 metaclass ,找到了,就使用 Model 中定义的 metaclass 的 ModelMetaclass 来创建 User 类,也就是说, metaclass 可以隐式地继承到子类,但子类自己却感觉不到。
可以定义各种操作数据库的方法,比如 save() , delete() , find() , update 等等。
class Model(dict, metaclass=ModelMetaclass): def __init__(self, **kw):
super(Model, self).__init__(**kw) def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Model' object has no attribute '%s'" % key) def __setattr__(self, key, value):
self[key] = value 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))
别的一些写在这里
参考链接:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014323389656575142d0bcfeec434e9639a80d3684a7da000
解释:https://www.jianshu.com/p/ac8a9bb57ec3
说实话,第一遍看完廖老师的ORM我是完全懵逼的,这技术、这思想真是秀啊,可是这技术太高端了、对于我这样的小白来说跨度太大了。可是看不懂能怎么办啊、于是又看别的orm介绍,刚好找到一篇别人写的ORM学习笔记,我觉得很有参考价值,他根据自己的了解把教程中的ORM教程的各个步骤给做了一个解释。配合这个,我终于能看懂一些了。
1)作用
ORM(Object Relationship Mapping) 的全程是对象关系映射,这种思想的要点在于要把后台对数据库的各种操作如增删改查中的一些步骤给抽象出来,把数据表映射成一个类,表中的行给作为一个实例,行中的每个字段作为属性,这样以来以前对数据库插入一行数据的操作就可以简化为
user=User(id="100001",name="Andy",password="*****")
user.save() //保存到数据库
这个ORM和三层架构好像有一些相似之处,他们都是将数据与SQL独立开来,让使用时只需要传递数据,调用方法,而不去一遍一遍的拼接sql语句。
弄清楚了:ORM包括字段类Field和Model类的实现
python ORM理解、元类的更多相关文章
- 深刻理解Python中的元类metaclass(转)
本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...
- 深刻理解Python中的元类(metaclass)
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- [转] 深刻理解Python中的元类(metaclass)
非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...
- [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式
使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...
- 深刻理解Python中的元类(metaclass)【转】
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- 深刻理解Python中的元类(metaclass)以及元类实现单例模式
在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...
- 深入理解Python中的元类(metaclass)
原文 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍 ...
- 深度理解python中的元类
本文转自:(英文版)https://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python (翻译版) http:// ...
- python——深刻理解Python中的元类(metaclass)
译注:这是一篇在Stack overflow上 很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉 ...
- python基础——使用元类
python基础——使用元类 type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello. ...
随机推荐
- 洛谷P1067 多项式输出(模拟)
题目描述 一元 n 次多项式可用如下的表达式表示: 其中,aixi称为 i 次项,ai 称为 i 次项的系数.给出一个一元多项式各项的次数和系数,请按照如下规定的格式要求输出该多项式: 1. 多项式中 ...
- html5+css3+javascript 自定义弹出窗口
效果图: 源码: 1.demo.jsp <%@ page contentType="text/html;charset=UTF-8" language="java& ...
- svn创建分支的做法
作者:朱金灿 来源:http://blog.csdn.net/clever101 1. 首先选择你要创建分支的工作目录,如下图: 2.选择要创建分支的路径.注释以及版本,选择HEADrevision ...
- 机器学习(十一) 支持向量机 SVM(上)
一.什么是支撑向量机SVM (Support Vector Machine) SVM(Support Vector Machine)指的是支持向量机,是常见的一种判别方法.在机器学习领域,是一个有监督 ...
- Mysql学习总结(27)——Mysql数据库字符串函数
注:sql的移植性比较强,函数的移植性不强,一般为数据库软件特有,例如mysql有mysql的函数,oracle有oracle的函数. 1.concat连接字符串: 从上图中可以看出,直接使用sele ...
- Qt 学习之路问题
Qt5 cannot include the file QMainWindow add "greaterThan(QT_MAJOR_VERSION, 4): QT += widgets&qu ...
- 洛谷 P2758 编辑距离
P2758 编辑距离 题目描述 设A和B是两个字符串.我们要用最少的字符操作次数,将字符串A转换为字符串B.这里所说的字符操作共有三种: 1.删除一个字符: 2.插入一个字符: 3.将一个字符改为另一 ...
- JS在页面限制checkbox最大复选数
应该是挺简单的代码, 记录一下分享. 首先最直接的想法就是使用循环, 用局部变量记录已选的checkbox, 达到最大值就将余下的checkbox都禁止选择, 例如以下: <!DOCTYPE h ...
- 【翻译自mos文章】开启dblink的 oracle net trace/tracing --对dblink进行跟踪的方法
开启dblink的 oracle net trace/tracing --对dblink进行跟踪的方法. 參考原文: DBLINK: How to Enable Oracle Net Tracing ...
- CG 内置函数 和 HLSL 内置函数
CG 内置函数 英伟达官网链接: http://http.developer.nvidia.com/Cg/index_stdlib.html absacosallanyasinatan2atanbi ...