关于元类,我写过一篇,如果你只是了解元类,看下面这一篇就足够了。

Python面向对象之类的方法和属性

本篇是深度解剖,如果你觉得元类用不到,呵呵,那是因为你不了解Django。

在Python中有一个type类,所有的类都是基于type类生成的,可谓万物之母。

如此广袤无垠的python生态圈,都是由type产生出来的。

Python面向对象总计包含五大部分:

常用部分:

3.class(类,或者叫实例生成器)

4.instance(实例)

5.实例的各种属性与方法,我们平常使用python时,调用的就是它们。

不常用部分(类从何而来):

1.type

2.metaclass(元类,或者叫类生成器)

两种方式创建类:

# 创建一个Hello类,拥有属性say_hello
class Hello():
def say_hello(self, name='gregory'):
print( 'Hello, %s.'% name)
# 从Hello类创建一个实例hello
hello =Hello()
# 使用hello调用方法say_hello
hello.say_hello() def func(self, name='gregory'):
# 创建函数func
print('Hi, %s.'% name)
Hi= type('Hi', (object,), dict(say_hello=func))
# 通过type创建Hi class
hello=Hi()
hello.say_hello()

效果一样的。

Hi= type('Hi', (object,), dict(say_hello=func))

第一个参数: 类名。我是谁。

第二个参数:当前类的基类。我从哪里来,也就是我的“父类”,以上实例中我的父类是“object”——python中一种非常初级的类。

第三个参数:类的成员。我要到哪里去,将需要调用的方法和属性包含到一个字典里,再作为参数传入。以上实例中,say_hello方法包装进了字典中。

type可以直接生成类(class),但也可以先生成元类(metaclass),再使用元类批量定制类(class)。

元类均被命名后缀为Metalass,元类的生命周期:

class SayMetaClass(type):
#元类是由“type”衍生而出,所以父类需要传入type。
def __new__(cls, name, bases, attrs):
#元类的操作都在 __new__中完成,它的第一个参数是将创建的类,之后的参数即是三大永恒命题:类名,基类,类的成员。 attrs['say_'+ name] =lambda self, value, saying=name:print(saying + ','+ value +'!')
#创造属性和方法,由元类创建的类叫“Hello”,那创建时就自动有了一个叫“say_Hello”的类方法
# 然后又将类的名字“Hello”作为默认参数saying,传到了方法里面。
# 然后把hello方法调用时的传参作为value传进去,最终打印出来。 return type.__new__(cls, name, bases, attrs)
#传承类名,父类,属性 class Hello(object, metaclass =SayMetaClass):
# 创建类,通过元类创建的类,第一个参数是父类,第二个参数是metaclass
pass hello =Hello()# 创建实列
hello.say_Hello( 'gregory')# 调用实例方法 class Nihao(object,metaclass=SayMetaClass):
pass nihao=Nihao()
nihao.say_Nihao("greg 李")

应用:Django的核心思想是“Object Relational Mapping”,即对象-关系映射,简称ORM。

这是Django的一大难点,但学完了元类,一切变得清晰。你对Django的理解将更上一层楼!

通过元类创建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) 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') 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) class Model(dict, metaclass=ModelMetaclass):
def __init__(self, **kwarg):
super(Model, self).__init__(**kwarg) def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError("'Model' object has no attribute '%s'" % key) def __setattr__(self, key, value):
self[key] = value # 模拟建表操作
def save(self):
fields = []
args = []
for k, v in self.__mappings__.items():
fields.append(v.name)
args.append(getattr(self, k, None))
sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join([str(i) for i in args]))
print('SQL: %s' % sql)
print('ARGS: %s' % str(args)) class User(Model):
# 定义类的属性到列的映射:
id = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password') u = User(id=12345, name='Gregory', email='292409083@qq.com', password='iamgreg')
u.save()

这是Django中的Model版块核心原理!

运行结果:

Found model: User
Found mapping: id ==> <IntegerField:id>
Found mapping: name ==> <StringField:username>
Found mapping: email ==> <StringField:email>
Found mapping: password ==> <StringField:password>
SQL: insert into User(id,username,email,password) values (12345,Gregory,292409083@qq.com,iamgreg)
ARGS: [12345, 'Gregory', '292409083@qq.com', 'iamgreg']

Python面向对象篇之元类,附Django Model核心原理的更多相关文章

  1. python 面向对象进阶之元类metaclass

    一:知识储备 exec exec:三个参数 参数一:字符串形式的命令 参数二:全局作用域(字典形式),如果不指定,默认为globals() 参数三:局部作用域(字典形式),如果不指定,默认为local ...

  2. 【转】python面向对象中的元类

    type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello.py模块: class Hel ...

  3. python 面向对象十二 元类

    一.类也是对象 只要使用关键字class,Python解释器在执行的时候就会创建一个对象.下面的代码段: class ObjectCreator(object): pass 将在内存中创建一个对象,名 ...

  4. python 面向对象编程 之 元类

    元类是类的类,使我们自定义的类,即我们用class定义类本质就是元类,是类的模板 四步走: 一:控制class定义类的过程 1.先拿到类名 2.在拿到基类 3.执行类体代码,得到名称空间的dict 4 ...

  5. 神级程序员通过两句话带你完全掌握Python最难知识点——元类!

    千万不要被所谓"元类是99%的python程序员不会用到的特性"这类的说辞吓住.因为 每个中国人,都是天生的元类使用者 学懂元类,你只需要知道两句话: 道生一,一生二,二生三,三生 ...

  6. Python基础(九) type元类

    python元类:type()    元类是python高阶语法. 合理的使用可以减少大量重复性的代码. 元类实际上做了以下三方面的工作: 干涉创建类的过程 修改类 返回修改之后的类 为什么使用元类? ...

  7. Python入门之Python的单例模式和元类

    一.单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在. 当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上 ...

  8. 30个类手写Spring核心原理之动态数据源切换(8)

    本文节选自<Spring 5核心原理> 阅读本文之前,请先阅读以下内容: 30个类手写Spring核心原理之自定义ORM(上)(6) 30个类手写Spring核心原理之自定义ORM(下)( ...

  9. 两句话掌握python最难知识点——元类

    千万不要被所谓“元类是99%的python程序员不会用到的特性”这类的说辞吓住.因为每个中国人,都是天生的元类使用者 学懂元类,你只需要知道两句话: 道生一,一生二,二生三,三生万物 我是谁?我从哪来 ...

随机推荐

  1. java程序员该工作还是游戏?

    前阵子我终于下定决心,删掉了硬盘里所有的游戏. 身为一个程序猿,每天都要和各种新技术打交道,闲暇时间,总还得看一下各大论坛,逛逛博客园啥的,给自己充充电.游戏的话,其实我自小就比较喜欢,可以算是一种兴 ...

  2. 【京东详情页】——原生js爬坑之放大镜

    一.引言 在商城的详情页中,放大镜的功能是很常见的.这里京东详情页就要做一个仿放大镜的效果,预览如下: 二.实现原理 实际上,放大镜的实现是单纯用几个div,鼠标移入其中一个小图div,触发事件显示另 ...

  3. django ajax练习

    这几天遇到了django ajax请求出错的问题,总结一下 前端js:我这里创建的是一个字典格式的数据,前端js收到字典之后也是要用字典的形式去解包后台传送过来的数据,比如我下面的写法:data['s ...

  4. 我真的知道JavaScript吗?

    JavaScript 说说JavaScript 接触JavaScript时间其实已经不短了,之前一直是半瓶酱油,东凑西凑的收集相关的知识.并没有完整系统的学习过JavaScript,觉得JavaScr ...

  5. Android ListView getViewTypeCount 的返回值问题解决

    最近在学慕课网上的一个实战课程,期间有一个智能聊天机器人模块. 聊天界面通过 ListView 显示,用 Adapter 加载.一般来说,单对单的聊天,两者发出的话分别列在聊天页面的左右两边.所以,在 ...

  6. There is no getter for property named xxx' in 'class java.lang.xxx'

    在xxxMapper.xml我们使用sql片段来提高sql代码的复用性,当时新手传入参数时常常出现这样的错误: There is no getter for property named xxx' i ...

  7. linux命令和awk

    1.统计一下代码量 find . -name "*.py" | xargs wc -l | awk 'BEGIN {size = 0} { size+=$1} END{print ...

  8. C语言/原子/编译,你真的明白了吗?

    说到原子,类似于以下的代码可能人人都可以看出猫腻. #include <stdio.h> #include <pthread.h> ; void* mythread(void* ...

  9. SAP 月结F.19与GR/IR

    http://blog.sina.com.cn/s/blog_3eeba40101008v75.html 为什么要做月结?月结究竟都结些啥? 月结的目的和手段都不知道,只知道一部分.月结,为了出资产负 ...

  10. 开发人员的福音:微软、谷歌、Mozilla将他们所有的web API文档放在同一个地方

    Tips 原文作者:Liam Tung  原文地址:Developers rejoice: Microsoft, Google, Mozilla are putting all their web A ...