TOP

Python3.7 dataclass使用指南
2019-02-07 22:07:58 】 浏览:100
Tags:Python3.7 dataclass 使用指南

dataclass的定义位于PEP-557,根据定义一个dataclass是指“一个带有默认值的可变的namedtuple”,广义的定义就是有一个类,它的属性均可公开访问,可以带有默认值并能被修改,而且类中含有与这些属性相关的类方法,那么这个类就可以称为dataclass,再通俗点讲,dataclass就是一个含有数据及操作数据方法的容器。


乍一看可能会觉得这个概念不就是普通的class么,然而还是有几处不同:


基于上述原因,通常自己实现一个dataclass是繁琐而无聊的,而dataclass单一固定的行为正适合程序为我们自动生成,于是dataclasses模块诞生了。


配合类型注解语法,我们可以轻松生成一个实现了__init____repr____cmp__等方法的dataclass:


同时使用dataclass也有一些好处,它比namedtuple更灵活。同时因为它是一个常规的类,所以你可以享受继承带来的便利。


我们分x步介绍dataclass的使用,首先是如何定义一个dataclass。


dataclasses模块提供了一个装饰器帮助我们定义自己的数据类:


我们定义了一个描述某种程序语言特性的数据类——Lang,在接下来的例子中我们都会用到这个类。


在数据类被定义后,会根据给出的类型注解生成一个如下的初始函数:


可以看到初始化操作都已经自动生成了,让我们试用一下:


例子中可以看出__repr____eq__方法也已经为我们生成了,如果没有其他特殊要求的话这个dataclass已经具备了投入生产环境的能力,是不是很神奇?


dataclass的魔力源泉都在dataclass这个装饰器中,如果想要完全掌控dataclass的话那么它是你必须了解的内容。


装饰器的原型如下:


dataclass装饰器将根据类属性生成数据类和数据类需要的方法。


我们的关注点集中在它的kwargs上:


有默认值的属性必须定义在没有默认值的属性之后,和对kw参数的要求一样。


上面我们偶尔提到了field的概念,我们所说的数据类属性,数据属性实际上都是被field的对象,它代表着一个数据的实体和它的元信息,下面我们了解一下dataclasses.field


先看下field的原型:


通常我们无需直接使用,装饰器会根据我们给出的类型注解自动生成field,但有时候我们也需要定制这一过程,这时dataclasses.field就显得格外有用了。


default和default_factory参数将会影响默认值的产生,它们的默认值都是None,意思是调用时如果为指定则产生一个为None的值。其中default是field的默认值,而default_factory控制如何产生值,它接收一个无参数或者全是默认参数的callable对象,然后用调用这个对象获得field的初始值,之后再将default(如果值不是MISSING)复制给callable返回的这个对象。


举个例子,对于list,当复制它时只是复制了一份引用,所以像dataclass里那样直接复制给实例的做法的危险而错误的,为了保证使用list时的安全性,应该这样做:


当初始化C的实例时就会调用list()而不是直接复制一份list的引用:


数据污染得到了避免。


init参数如果设置为False,表示不为这个field生成初始化操作,dataclass提供了hook——__post_init__供我们利用这一特性:


__post_init____init__后被调用,我们可以在这里初始化那些需要前置条件的field。


repr参数表示该field是否被包含进repr的输出,compare和hash参数表示field是否参与比较和计算hash值。metadata不被dataclass自身使用,通常让第三方组件从中获取某些元信息时才使用,所以我们不需要使用这一参数。


如果指定一个field的类型注解为dataclasses.InitVar,那么这个field将只会在初始化过程中(__init____post_init__)可以被使用,当初始化完成后访问该field会返回一个dataclasses.Field对象而不是field原本的值,也就是该field不再是一个可访问的数据对象。举个例子,比如一个由数据库对象,它只需要在初始化的过程中被访问:


这个例子中会返回c.ic.j的数据,但是不会返回c.database的。


dataclasses模块中提供了一些常用函数供我们处理数据类。


使用dataclasses.asdictdataclasses.astuple我们可以把数据类实例中的数据转换成字典或者元组:


使用dataclasses.is_dataclass可以判断一个类或实例对象是否是数据类:


python3.7引入dataclass的一大原因就在于相比namedtuple,dataclass可以享受继承带来的便利。


dataclass装饰器会检查当前class的所有基类,如果发现一个dataclass,就会把它的字段按顺序添加进当前的class,随后再处理当前class的field。所有生成的方法也将按照这一过程处理,因此如果子类中的field与基类同名,那么子类将会无条件覆盖基类。子类将会根据所有的field重新生成一个构造函数,并在其中初始化基类。


看个例子:


Lang的field被Python继承了,而C中的x则覆盖了Base中的定义。


没错,数据类的继承就是这么简单。


合理使用dataclass将会大大减轻开发中的负担,将我们从大量的重复劳动中解放出来,这既是dataclass的魅力,不过魅力的背后也总是有陷阱相伴,最后我想提几点注意事项:


只要避开这些陷阱,dataclass一定能成为提高生产力的利器。



Python3.7 dataclass使用指南 https://www.cppentry.com/bencandy.php?fid=54&id=207330

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++随机排序容器中的元素 下一篇Java中创建线程的三种方式以及区别