python元类 orm_python-进阶-元类在ORM上的应用详解
ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。
要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。
让我们来尝试编写一个ORM框架。
编写底层模块的第一步,就是先把调用接口写出来。比如,使用者如果使用这个ORM框架,想定义一个User类来操作对应的数据库表User,我们期待他写出这样的代码:
期望代码
class User(Model): # User类,继承Model
# 定义类的属性到列的映射: 右边的 StringField(‘username’),这里StringField是类,类(‘username’)是输入__init__绑定的参数,所以得到的是一个实例,正好对应value
id = IntegerField('id') # ⚠️id理解为一个变量不好,id理解成一个key最恰当,=右边的则是value,这里对应的就是数据库字典的id数据
name = StringField('username') # name是类属性,具体可参考类属性与实例属性定义,类调用属性就是User.name
email = StringField('email') # id name email password 均是User的属性,User的实例可以直接调用
password = StringField('password') # User().name = StringField(‘username’),直接调用,也就是对应一个user的表,表里的name叫SF()
# 创建一个实例:
u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd') # ⚠️对照这个效果可以想通一二了
# 保存到数据库:
u.save()
其中,父类Model和属性类型StringField、IntegerField是由ORM框架提供的,剩下的魔术方法比如save()全部由metaclass自动完成。虽然metaclass的编写会比较复杂,但ORM的使用者用起来却异常简单。
现在,我们就按上面的接口来实现该ORM。
首先来定义Field类,它负责保存数据库表的字段名和字段类型
class Field(object): # 对应数据库中保存的字段名和字段类型
def __init__(self, name, column_type): # 添加__init__(self,name)方法后,类的实例必须是StringField(‘某name’),正好呼应上方的期望代码
self.name = name # 字段名
self.column_type = column_type # 字段类型
def __str__(self): # 输入print(xxx)会自动调用__str__,它为了使打印结果更好看而已,Python 定义了__str__()和__repr__()两种方法,__str__()用于显示给用户,而__repr__()用于显示给开发人员。
return '' % (self.__class__.__name__, self.name) # 不使用print(xxx)而是直接输入实例xxx,则该行不会打印显示出来,看起来就很丑
在Field的基础上,进一步定义各种类型的Field,比如StringField,IntegerField等等:
class StringField(Field): # ✌️通过比对测试,StringField.name = name, StringField.column_type = varchar(100).
def __init__(self, name): # 实例属性,`实例.name`调用
super(StringField, self).__init__(name, 'varchar(100)') # 为什么这么设计?super最后跟的参数是(name,’varchar(100)’)一个变量name,一个值。为了就是不让人去修改 column_type这个参数而已
# ⚠️super的用法,继承父类的方法而自己无需定义, super(StringFileld,self).__init__这段是套路,都一样,super后面跟的子类名+self,只有最后的(name,’varchar(100)’)表示继承父类的哪些属性
------------------------测试------------------------------
In [67]: test = StringField('love')
In [68]: type(test)
Out[68]: __main__.StringField
In [70]: test.column_type
Out[70]: 'varchar(100)'
In [71]: test.name
Out[71]: 'love'
------------------------------------------------------------
class IntegerField(Field): # ⚠️子类继承这些方法
def __init__(self, name):
super(IntegerField, self).__init__(name, 'bigint') # __init__()这样的写法,可参考我的super文章
下一步,就是编写最复杂的ModelMetaclass了:(重点 难)
class ModelMetaclass(type):
# 元类必须实现__new__方法,当一个类指定通过某元类来创建,那么就会调用该元类的__new__方法
# 该方法接收4个参数
# cls为当前准备创建的类的对象
# name为类的名字,创建User类,则name便是User
# bases类继承的父类集合,创建User类,则base便是Model
#
python元类 orm_python-进阶-元类在ORM上的应用详解相关推荐
- python类继承中构造方法_第8.3节 Python类的__init__方法深入剖析:构造方法与继承详解...
第8.3节Python类的__init__方法深入剖析:构造方法与继承详解 一. 引言 上两节介绍了构造方法的语法及参数,说明了构造方法是Python的类创建实例后首先执行的方法,并说明如果类没 ...
- C++ - 派生类(derived class) 的 构造(construct) 和 析构(destruct)顺序 详解
派生类(derived class) 的 构造(construct) 和 析构(destruct)顺序 详解 本文地址: http://blog.csdn.net/caroline_wendy/art ...
- Scala进阶之路-面向对象编程之类的成员详解
Scala进阶之路-面向对象编程之类的成员详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Scala中的object对象及apply方法 1>.scala 单例对象 ...
- python调用shell脚本的参数_使用python执行shell脚本 并动态传参 及subprocess的使用详解
最近工作需求中 有遇到这个情况 在web端获取配置文件内容 及 往shell 脚本中动态传入参数 执行shell脚本这个有多种方法 最后还是选择了subprocess这个python标准库 subpr ...
- python计算各类型电影的评分_【Python数据科学实战项目】之 基于MovieLens的影评趋势分析|详解...
原标题:[Python数据科学实战项目]之 基于MovieLens的影评趋势分析|详解 注:图片源于https://movielens.org/ 1. 项目任务 1.1 数据来源 本项目使用Group ...
- 基于点击量的趋势分析python_【Python数据科学实战项目】之 基于MovieLens的影评趋势分析详解...
原标题:[Python数据科学实战项目]之 基于MovieLens的影评趋势分析详解 本文转自: 数据科学DataScience 注:图片源于https://movielens.org/ 1. 项目任 ...
- [python opencv 计算机视觉零基础到实战] 四、了解色彩空间及其详解
一.学习目标 了解什么是色彩空间 了解opencv中色彩空间的转换 目录 [python opencv 计算机视觉零基础到实战] 一.opencv的helloworld [[python opencv ...
- python整数池_对Python中小整数对象池和大整数对象池的使用详解
1. 小整数对象池 整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间. Python 对小整数的定义是 [-5, 256] 这些整数对象是提 ...
- 站长在线Python精讲:在Python中使用split()方法分割、使用join()方法合并字符串详解
欢迎你来到站长在线的站长学堂学习Python知识,本文学习的是<在Python中使用split()方法分割.使用join()方法合并字符串详解>.本知识点主要内容有:在Python中使用s ...
最新文章
- pandas.describe()参数含义
- Linux线程-互斥锁pthread_mutex_t
- 皮一皮:直男只想说一句,表白?是表特别白吗?
- android 去掉蓝牙传输文件功能_iPhone还在用蓝牙传输照片?这个功能更好用还快哟,了解一下...
- 深度学习(十)keras学习笔记
- iOS开发 适配iOS10以及Xcode8-b
- 知乎:全球发售2600万股销售股份 每股发售价51.8港元
- Apache CXF实战之七 使用Web Service传输文件
- 学考语言成绩c对高考有影响吗_广东2020学考招录办法来了,实现平行志愿,计划不低于年度总计划50%...
- 1 恢复MySQL误删数据
- JDK1.8源码(十一)——java.util.TreeMap类
- SAP 服务器文件上传和下载
- 利用Excel制作库房管理系统
- 人工智能万亿市场待挖掘
- Topaz Gigapixel AI打开软件闪退及加载图片闪退 解决办法
- 盒式滤波器BoxFilter
- 安卓投屏传输手机声音到电脑最简单的方式
- C语言输入一个日期,计算这一天是周几
- 图片存放在服务器还是数据库里的解释?
- r语言list 转换成 vector
热门文章
- MySQL从入门到搞定实战
- html旋转墙壁效果,css3实现照片墙效果,鼠标悬浮时旋转放大并摆正
- 龙格库塔法解微分方程组的matlab程序,MATLAB实例源码教程:龙格库塔法求解微分方程组源代码实例.doc...
- Redis入门教程(一)
- php查询当前session,php查看当前Session的ID方法
- gdb coredump
- hdfs文档存储服务器,一文读懂HDFS分布式存储框架分析
- 有没有可以翻译c语言程序的软件下载,程序员秒懂!分享一款很优雅的翻译软件...
- php 如何把u5fb,php如何将json中的unicode编码转为汉字?
- bootstrap的php写在哪里,bootstrap用什么编辑器写