# 一张表一个类,表内每一行就是一个实例
'''
一个单独的元类使用的程序分析。
''' 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) # self.__class__:得到当前实例的类 self.__class__.__name__:得到当前实例的类的名字
# self.name:实例名字 __repr__ = __str__ class StringField(Field):
def __init__(self, name):
super(StringField, self).__init__(name, 'varchar(100)') class IntegerField(Field):
def __init__(self, name):
super(IntegerField, self).__init__(name, 'bigint') # ModelMetaclass这个元类的__new__()方法在本程序中的作用:
# 1.在依据ModelMetaclass创建Model时,由Model向元类传入的参数为:cls:<class '__main__.ModelMetaclass>;name:Model;bases()传入的bases是一个tuple:(<class 'dict'>,),attrs是一个由Model类中的所有的方法名和方法函数地址组成的dict.
# 然后再传入该元类后,执行__new__(),由于name=='Model'所以返回由type('Model', (dict,), attrs)所组成的类。return了,不往下执行。
# 2.在准备创建User类时,可以见class User上的注释。此时name==User。在__new__()内执行时。if失效。往后运行,创建一个名为mappings的dict。mappings的作用是用来存储此时User里面的4个属性(id,name,password,email).并将作为一个属性返回。
# 由于attrs包含了User中的所有的属性。所以先要用isinstance(v,Field)判断是不是id/name/password/email中的一个。若找到,则复制如mappings中。
# 删除User的4个id/name/password/email属性(防止造成实例的属性遮盖类的同名属性)。
# 添加两个属性__mappings__和__table__。并把最后的attrs作为最后要生成的名为User的类的所有方法。 class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
# print('hello',cls,'---',name,'---',bases,'---',attrs)
if name == 'Model': # 如果名字==Model。那么久用type创建一个类。在这里,name:要创建的类的名字;bases:要创建的类的父类;attrs:类的方法与函数对照字典。
# print(attrs)
return type.__new__(cls, name, bases, attrs)
# return super().__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():
# print([(k, v) for k, v in attrs.items() if isinstance(v, Field)])
attrs.pop(k)
attrs['__mappings__'] = mappings
attrs['__table__'] = name
# print(attrs)
return type.__new__(cls, name, bases, attrs) class Model(dict, metaclass=ModelMetaclass):
def __init__(self, **kw):
# print(Model.mro())
# 调用父类dict类的__init__方法,需要传入一个dict。
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():
# print(v.name)
fields.append(v.name)
params.append('?')
# 当u=User(......)后,u就具有了4个属性u.id=12345 u.name='Michael' u.email='test@orm.org' u.password='my-pwd'
args.append(getattr(self, k, None))
sql = 'insert into %s (%s) values (%s)' % (self.__table__,
','.join(fields),
','.join(params))
# join()函数
# 语法: 'sep'.join(seq) 该例为:','.join(fields) 对应的:sep=, seq=fields.
# 参数说明
# sep:分隔符。可以为空
# seq:要连接的元素序列、字符串、元组、字典
# 上面的语法即:以sep作为分隔符,将seq所有的元素合并成一个新的字符串
# 返回值:返回一个以分隔符sep连接各个元素后生成的字符串
print('SQL: %s' % sql)
# print(args)
print('ARGS: %s' % str(args)) # 当用户定义一个class User(Model)时,Python解释器首先在当前类User的定义中查找metaclass,如果没有找到,
# 就继续在父类Model中查找metaclass,找到了,就使用Model中定义的metaclass的ModelMetaclass来创建User类,
# 也就是说,metaclass可以隐式地继承到子类,但子类自己却感觉不到。 # 在创建User时,程序会先执行完里面的4条属性声明语句。然后再将包含该4条属性和所有的方法组成一个dict。传入ModelMetaclass的__new__中。 # 通过使用元类,程序员可以在这里自定义一个类(数据库的一张表)需要输入哪些元素。 class User(Model):
id = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password') # 在这里时,User类里面没有4个单独的id/name/password/email属性,只有__mappings__和__table__属性。 # print(type(User.id))
# print(dir(User))
u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')
# print(u.name.name)
# print(u.id.name)
# print(u.email.name)
# print(u.password.name)
# print(dir(u.id))
# print(u.id.name)
u.save()
# print(dir(Model))

python的MetaClass的代码分析。基于廖雪峰博客代码的更多相关文章

  1. step2: 爬取廖雪峰博客

    #https://zhuanlan.zhihu.com/p/26342933 #https://zhuanlan.zhihu.com/p/26833760 scrapy startproject li ...

  2. git入门笔记汇总——(廖雪峰博客git入门)

    本文内容是对廖雪峰老师Git教程做的笔记,外加一些自己的学习心得,还抱着学以致用的心态来实践一番 如有显示错误 请移步本人github:git教程小结 Git学习笔记 Git简介 安装Git 创建版本 ...

  3. python 3 廖雪峰博客笔记(二) python解释器

    python 解释器用于理解 python代码,存在多种python解释器 CPython 官方版本python解释器,用C语言开发,使用最广泛 IPython 基于CPython,在交互方式上有所增 ...

  4. python 1 学习廖雪峰博客

    输出 用print()在括号中加上字符串,就可以向屏幕上输出指定的文字.比如输出'hello, world',用代码实现如下: >>> print('hello, world') p ...

  5. python 3 廖雪峰博客笔记(三) 命令行模式与交互模式

    python 的代码一般保存为 .py结尾的文本文件格式 比如 add.py 里写下如下内容 100 + 200 执行 add.py有两种方式: 1. 命令行方式:将python代码写入脚本中执行 p ...

  6. python 3 廖雪峰博客笔记(一) python特性

    python 是一种解释性语言,代码在执行时会一行一行翻译成CPU能理解的机器语言. python 的特点是简单优雅. python 的优点是 代码优雅 基础代码库丰富,包括网络.文件.GUI.数据库 ...

  7. git 廖雪峰博客笔记

    其他参考 http://www.softwhy.com/article-8498-1.html 本地模拟多用户来学习 参考   其实就是克隆两个目录,两个目录的git config 不同的名字和邮箱, ...

  8. Linux内核分析第二周学习博客——完成一个简单的时间片轮转多道程序内核代码

    Linux内核分析第二周学习博客 本周,通过实现一个简单的操作系统内核,我大致了解了操作系统运行的过程. 实验主要步骤如下: 代码分析: void my_process(void) { int i = ...

  9. 基于Hexo搭建博客并部署到Github Pages

    基于Hexo搭建博客并部署到Github Pages 之前在简书上写东西,觉得自己还是太浮躁.本来打算用Flask自己写一个,以为是微框架就比较简单,naive.HTML.CSS.JS等都要学啊,我几 ...

随机推荐

  1. Python学习---Django路由系统【all】

    Django URL (路由系统) Django URL (路由系统): URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL模式以及要为该URL模式调用的视图函数之间的映 ...

  2. UDF/UDAF开发总结

    参考文章: https://www.cnblogs.com/itxuexiwang/p/6264547.html https://www.cnblogs.com/eRrsr/p/6096989.htm ...

  3. January 07 2017 Week 1st Saturday

    Procrastination is the thief of time. 拖延乃是光阴之窃贼. My parents always tell me that things ought to be d ...

  4. 四、并行编程 - 并行LINQ(PLINQ) 的使用。AsParallel

    用于对内存中的数据做并行运算,也就是说其只支持 LINQ to Object 的并行运算 一.AsParallel(并行化) 就是在集合后加个AsParallel(). 例如: , ); == ); ...

  5. 021.12 IO流 ObjectStream对象序列化

    内容:通过文件存储对象我们遇到的问题,需要保存对象到硬盘中,如何解决这个就是用来解决的 用法:1.创建流对象FileOutputstream2.创建ObjectOutputStream对象与FileO ...

  6. 【SQL.基础构建-第三节(3/4)】

    --      Tips:聚合和排序 --    一.对表进行聚合查询 -- 1.聚合函数 -- (1)5 个常用函数: -- ①COUNT:计算表中的记录(行)数. -- ②SUM:计算表中数值列的 ...

  7. mysql install steps

    the official documents for mysql 5.6 install key steps: # Preconfiguration setup shell> groupadd ...

  8. 设置python的默认编码方式为utf-8

    在python的Lib\site-packages文件夹下新建一个sitecustomize.py,然后通过sys.getdefaultencoding()获取当前的默认编码 内容为:

  9. 由JDK源码学习ArrayList

    ArrayList是实现了List接口的动态数组.与java中的数组相比,它的容量能动态增长.ArrayList的三大特点: ① 底层采用数组结构 ② 有序 ③ 非同步 下面我们从ArrayList的 ...

  10. JavaScript的事件的处理函数(鼠标,键盘,HTML)

    事件处理函数概述 JavaScript 可以处理的事件类型为:鼠标事件.键盘事件.HTML 事件 所有的事件处理函数都会都有两个部分组成,on + 事件名称,例如 click 事件的事件处理函数就是: ...