资讯专栏INFORMATION COLUMN

再有人问什么是元类,就把这篇文章扔给他!

王岩威 / 2476人阅读

摘要:同时,在元类中,我们还需要加上一个判断,只有在这个类创建时才需要控制其类的生成,其他的就不需要了。完整代码后台回复元类获取原创不易,如果文章对你有用的话,点赞留言转发是对我的最大支持日常学代码不止,还有美和乐趣

我之前在深入理解python中的类和对象中说过,python中的类也是一个对象,可以说是类对象,可以由type来创建类对象的。有了这个知识我们先看看下面这个函数:

这个可以根据我们传递的参数来指定生成相关的对象,可以说是很简单地动态创建类,我们再看看结果:

这里输入的参数为 user,所以最好的结果就是生成了 User 这个类,这个方法虽然是简单,但是当里面类的逻辑越来越多的时候这个类里写的代码就会非常地多,就会变得很臃肿了,不好看,所以这种方法不合适。

我们再看看 type() 这个方法,之前说它可以动态创建一个类,那我们现在看看到底怎样创建?

在pycharm编辑器上,进入 type() 的内部源码查看,可以看到:

第三行说的就是创建一个新类,接收的是三个参数,通过名字很容易就知道这三个参数的意义:

name:类的名称

bases:基类,就是所需要继承的类

dict:类的属性,包括方法

那既然知道了就创建一个来看看。

这个可以看到我创建了一个 person 的类,没有基类,注意基类这个接收的是一个元组,属性只有一个 name 属性。这个是不是很简单很直接,如果需要增加方法,也只是在 dict 参数加上对应的方法名即可,如下:

我们知道能创建类的类就是元类,所以说type也是一个元类。这个还比较简单,因为就三个参数,按照规则来就可以了,但是这个只能是动态生成类,不能对类的生成过程做操作,也就是说不能控制类是如何生成的,所以在 python3 中还有个元类:metaclass,这个也是可以动态创建类的,比 type这个方法能操作的东西多了,但同时也有点难。

在说metaclass之前,先说下类是如何生成的,类分两种。

普通的类,不通过 metaclass 来创建的,这个就简单,就是通过type来创建类对象。

第二种,就是使用 metaclass 的,这时就通过 metaclass 来创建类,如果此类没有,就会去寻找父类的 metaclass ,再没有,还是会继续往上找,直至找到。

再说下为什么要使用 metaclass 来创建类呢?

将创建类对象的过程委托给元类来做,不需要再在类内部来操作,这样代码的分离性比较强

可以检查该类有没有实现父类的那些抽象方法,没有重载的话就可以直接抛异常,不让创建成功

还有很多,以后见到再补充说明,还有就是你会见到很多框架都会使用metaclass 来创建类的,要想成为一名好的 python 工程师,元类这一关必须过的。

说了,那么多,举个小栗子来说明怎么使用 metaclass 来创建类吧!

可以看到,在类中指明 metaclass 来控制类的生成,这时所指向 metaclass 必须继承t ype 这个类才可以。我们还在 metaclass 这个类中通过修改__new__这个方法来控制类的实现,这时就可以将__init__和__new__这两个方法分离出来了。

下面再来通过实现一个 orm 框架类体现通过元类创建类的好处。因为大家都知道在python中使用 pymysql 这个库来操作 mysql 是很烦,所以才会有了这个 orm 框架,这里引用下廖雪峰的官网的一段话:

ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。

要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。

talk is cheap show you the code.

这个是我们在使用 orm 框架时希望是上面这样调用的,这里就简单定义两个字段 name 和 age,User 类中还有个内部类是 Meta ,这里面用了定义数据表的其他属性,与字段定义分开,所以里面定义了一个数据表名称。在使用 save() 方法保存的时候就是内部拼接 mysql 语句,等下实现。

接下来先对两个字段类实现。

这个是对 IntField 类的实现,可以看到里面很多逻辑,同时 CharField 这个类也是这样实现的。

接下来是对 metaclass 的实现

这个__new__的方法就是对类的生成的控制,我们可以断点看看,里面的参数是什么

可以看到,经过拆包,args可以分为三个参数,一个类名称,另一个为元组,就是基类,还有一个就是类的属性,所以可以把上面的参数改为下面的更好操作。

下面我们需要对attrs的参数里的字段进行抽取出来,但是在判断的时候需要判断的东西很多,比如需要判断是 CharField 或者 IntField 才进行抽取,这样如果字段多了的话写的代码就会很多,有一个技巧就是让所有的字段都共同继承一个基类 Field,然后判断是不是这个基类即可

这个元类基本上是完成了,最后记得调用父类的__new__进行返回,要不然会创建类对象失败,从而调用不了__init__方法来实例对象。

这里还有一个问题,就是用户在创建 User 时候可能会直接存入字段信息,就比如下面这个:

user = User("张三", 23)  


所以我们还需要在 User 类中实现 __init__ 方法,但是如果直接在 User 类中添加这个方法的话就不太好看了,我们可以再实现一个基类 BaseModel ,在这个类中添加 __init__ 方法,这样就比较好,而且还可以实现 save() 这个方法。

在使用了另一个基类 BaseModel 之后,将这个基类来用 metaclass 来实现,同时 User 就不需要实现 metaclass 了,只需要继承此基类就好,因为 meta class 会向上查找,只需要父类实现就可以了。同时,在元类 Model中,我们还需要加上一个判断,只有在 User 这个类创建时才需要控制其类的生成,其他的就不需要了。

这时再看看基类 BaseModel 的 __init__ 方法如何实现的。

通过 setattr() 方法来进行赋值就简单多了,不需要一个一个判断完再取出来。

剩下的就只有 save 方法没有实现了,这个方法就简单多了,只需要实现拼接 mysql 语句就可以了,这里需要拼接的语句是

sql = "insert user(name, age) values ("", 23)"  


再看看代码实现

以上就是整个 orm框架的实现了,是不是看起来很简单?却解决了 繁杂的 mysql 操作语句。

最后运行下就会看到一个完整的 mysql 语句出现。

如果我们在需要添加别的类型字段的话就只需要实现下这个类就好,其他的都不需要管了,是不是超级方便的?

写在最后

如果看不不懂得话建议多敲代码几篇,然后打上断点跟着代码一段一段思考,这样子就会好理解多了,还有就是看了很多遍还是不懂的话可以先放下,毕竟有 99% 的时候都不需要用这个元类,因为实在是太麻烦了,等以后回来再看也不迟。

完整代码后台回复「元类」获取

ps:原创不易,如果文章对你有用的话,点赞留言转发是对我的最大支持!

日常学python

代码不止bug,还有美和乐趣

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/42244.html

相关文章

  • 以后有面试官你跳跃表,你把这文章给他

    摘要:跳跃表的空间复杂度为。不过,二叉查找树是有可能出现一种极端的情况的,就是如果插入的数据刚好一直有序,那么所有节点会偏向某一边。例如这种接结构会导致二叉查找树的查找效率变为这会使二叉查找树大打折扣。假如我们要用某种数据结构来维护一组有序的int型数据的集合,并且希望这个数据结构在插入、删除、查找等操作上能够尽可能着快速,那么,你会用什么样的数据结构呢? 数组 一种很简单的方法应该就是采用数组了...

    nidaye 评论0 收藏0
  • 如果有人你ZooKeeper是什么把这文章给他

    摘要:所以,雅虎的开发人员就试图开发一个通用的无单点问题的分布式协调框架,以便让开发人员将精力集中在处理业务逻辑上。在立项初期,考虑到之前内部很多项目都是使用动物的名字来命名的例如著名的项目雅虎的工程师希望给这个项目也取一个动物的名字。 前言 提到ZooKeeper,相信大家都不会陌生。Dubbo,Kafka,Hadoop等等项目里都能看到它的影子。但是你真的了解 ZooKeeper 吗?如...

    suosuopuo 评论0 收藏0
  • [译]什么元类metaclass?

    摘要:如果还是没有找到,就会使用父类中的元类来创建类。元类通常用于处理比较复杂的情况。这是因为使用了元类,它会将中定义的字段转换成数据库中的字段。中所有数据类型都是对象,它们要么是类的实例要么是元类的实例。 原文地址:what is metaclass in Python?我的简书地址::nummy 类即对象 在理解元类之前,需要先掌握Python中的类,Python中类的概念与SmallT...

    zsirfs 评论0 收藏0
  • python 类和元类(metaclass)的理解和简单运用

    摘要:什么是元类刚才说了,元类就是创建类的类。类上面的属性,相信愿意了解元类细节的盆友,都肯定见过这个东西,而且为之好奇。使用了这个魔法方法就意味着就会用指定的元类来创建类了。深刻理解中的元类 (一) python中的类 今天看到一篇好文,然后结合自己的情况总结一波。这里讨论的python类,都基于python2.7x以及继承于object的新式类进行讨论。 首先在python中,所有东西都...

    zhangqh 评论0 收藏0
  • 以后有人你selenium是什么,你把这文章给他

    摘要:不同目标的自动化测试有不同的测试工具,但是任何工具都无不例外的需要编程的过程,实现源代码,也可以称之为测试脚本。 写在最前面:目前自动化测试并不属于新鲜的事物,或者说自动化测试的各种方法论已经层出不穷,但是,能够在项目中持之以恒的实践自动化测试的团队,却依旧不是非常多。有的团队知道怎么做,做的还不够好;有的团队还正在探索和摸索怎么做,甚至还有一些多方面的技术上和非技术上的旧系统需要重构……...

    Keven 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<