Python 3.7新功能之dataclass装饰器详解


Posted in Python onApril 21, 2018

前言

Python 3.7 将于今年夏天发布,Python 3.7 中将会有许多新东西:

  • 各种字符集的改进
  • 对注释的推迟评估
  • 以及对dataclass的支持

最激动人心的新功能之一是 dataclass 装饰器。

什么是 Data Class

大多数 Python 开发人员编写过很多像下面这样的类:

class MyClass:
 def __init__(self, var_a, var_b):
 self.var_a = var_a
 self.var_b = var_b

dataclass 可以为简单的情况自动生成方法,例如,一个__init__接受这些参数并将其分配给自己,之前的小例子可以重写为:

@dataclass
class MyClass:
 var_a: str
 var_b: str

那么通过一个例子来看看如何使用吧

星球大战 API

可以使用 requests 从星球大战 API 获取资源:

response = requests.get('https://swapi.co/api/films/1/')
dictionary = response.json()

让我们来看看 dictionary (简化过)的结果:

{
 'characters': ['https://swapi.co/api/people/1/',… ],
 'created': '2014-12-10T14:23:31.880000Z',
 'director': 'George Lucas',
 'edited': '2015-04-11T09:46:52.774897Z',
 'episode_id': 4,
 'opening_crawl': 'It is a period of civil war.\r\n … ',
 'planets': ['https://swapi.co/api/planets/2/', … ],
 'producer': 'Gary Kurtz, Rick McCallum',
 'release_date': '1977-05-25',
 'species': ['https://swapi.co/api/species/5/',…],
 'starships': ['https://swapi.co/api/starships/2/',…],
 'title': 'A New Hope',
 'url': 'https://swapi.co/api/films/1/',
 'vehicles': ['https://swapi.co/api/vehicles/4/',…]

封装 API

为了正确地封装一个 API,我们应该创建一个用户可以在其应用程序中使用的对象,因此,在Python 3.6 中定义一个对象来包含requests对 /films/endpoint的响应:

class StarWarsMovie:
 def __init__(self,
   title: str,
   episode_id: int,
   opening_crawl: str,
   director: str,
   producer: str,
   release_date: datetime,
   characters: List[str],
   planets: List[str],
   starships: List[str],
   vehicles: List[str],
   species: List[str],
   created: datetime,
   edited: datetime,
   url: str
   ):

 self.title = title
 self.episode_id = episode_id
 self.opening_crawl= opening_crawl
 self.director = director
 self.producer = producer
 self.release_date = release_date
 self.characters = characters
 self.planets = planets
 self.starships = starships
 self.vehicles = vehicles
 self.species = species
 self.created = created
 self.edited = edited
 self.url = url

 if type(self.release_date) is str:
  self.release_date = dateutil.parser.parse(self.release_date)

 if type(self.created) is str:
  self.created = dateutil.parser.parse(self.created)

 if type(self.edited) is str:
  self.edited = dateutil.parser.parse(self.edited)

仔细的读者可能已经注意到这里有一些重复的代码。

这是使用 dataclass 装饰器的经典案例,我们需要创建一个主要用来保存数据的类,只需一点验证,所以让我们来看看我们需要修改什么。

首先,data class 自动生成一些 dunder 方法,如果我们没有为 data class 装饰器指定任何选项,则生成的方法有:__init__,__eq__和__repr__,如果你已经定义了__repr__但没定义__str__,默认情况下 Python(不仅仅是 data class)将实现返回__repr__的输出__str__方法。因此,只需将代码更改为以下代码即可实现四种 dunder 方法:

@dataclass
class StarWarsMovie:
 title: str
 episode_id: int
 opening_crawl: str
 director: str
 producer: str
 release_date: datetime
 characters: List[str]
 planets: List[str]
 starships: List[str]
 vehicles: List[str]
 species: List[str]
 created: datetime
 edited: datetime
 url: str

我们去掉了__init__方法,以确保 data class 装饰器可以添加它生成的对应方法。不过,我们在这个过程中失去了一些功能,我们的 Python 3.6 构造函数不仅定义了所有的值,还试图解析日期,我们怎样才能用 data class 来做到这一点呢?

如果要覆盖 __init__,我们将失去 data class 的优势,因此,如果要处理任何附加功能可以使用新的 dunder 方法:__post_init__,让我们看看__post_init__方法对于我们的包装类来说是什么样子的:

def __post_init__(self):
 if type(self.release_date) is str:
  self.release_date = dateutil.parser.parse(self.release_date)

 if type(self.created) is str:
  self.created = dateutil.parser.parse(self.created)

 if type(self.edited) is str:
  self.edited = dateutil.parser.parse(self.edited)

就是这样! 我们可以使用 data class 装饰器在用三分之二的代码量实现我们的类。

更多好东西

通过使用装饰器的选项,可以为用例进一步定制 data class,默认选项是:

@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)
  • init决定是否生成__init__ dunder 方法
  • repr决定是否生成__repr__ dunder方法
  • eq对__eq__ dunder 方法也是如此,它决定相等性检查的行为(your_class_instance == another_instance)
  • order 实际上创建了四种 dunder 方法,它们确定所有检查小于,and/or,大于的行为,如果将其设置为 true,则可以对对象列表进行排序。

最后两个选项确定对象是否可以被哈希化,如果你想使用你的 class 的对象作为字典键的话,这是必要的。

更多信息请参考:PEP 557 -- Data Classes

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
python操作摄像头截图实现远程监控的例子
Mar 25 Python
python中常用的各种数据库操作模块和连接实例
May 29 Python
Python 快速实现CLI 应用程序的脚手架
Dec 05 Python
实例详解Matlab 与 Python 的区别
Apr 26 Python
Django stark组件使用及原理详解
Aug 22 Python
python3.6、opencv安装环境搭建过程(图文教程)
Nov 05 Python
python GUI库图形界面开发之PyQt5窗口布局控件QStackedWidget详细使用方法
Feb 27 Python
Python中内建模块collections如何使用
May 27 Python
利用python控制Autocad:pyautocad方式
Jun 01 Python
用Python 执行cmd命令
Dec 18 Python
Python从MySQL数据库中面抽取试题,生成试卷
Jan 14 Python
Python MNIST手写体识别详解与试练
Nov 07 Python
pandas or sql计算前后两行数据间的增值方法
Apr 20 #Python
对pandas进行数据预处理的实例讲解
Apr 20 #Python
pandas 两列时间相减换算为秒的方法
Apr 20 #Python
详谈pandas中agg函数和apply函数的区别
Apr 20 #Python
Python使用pip安装pySerial串口通讯模块
Apr 20 #Python
pandas apply 函数 实现多进程的示例讲解
Apr 20 #Python
python3+PyQt5图形项的自定义和交互 python3实现page Designer应用程序
Jul 20 #Python
You might like
PHP实现的猴王算法(猴子选大王)示例
2018/04/30 PHP
PHP实现防止表单重复提交功能【基于token验证】
2018/05/24 PHP
在Laravel5中正确设置文件权限的方法
2019/05/22 PHP
Thinkphp5+Redis实现商品秒杀代码实例讲解
2020/12/29 PHP
获取DOM对象的几种扩展及简写
2006/10/09 Javascript
简单三步,搞掂内存泄漏
2007/03/10 Javascript
23个Javascript弹出窗口特效整理
2011/02/25 Javascript
js URL参数的拼接方法比较
2012/02/15 Javascript
Jquery原生态实现表格header头随滚动条滚动而滚动
2014/03/18 Javascript
javascript类型系统——undefined和null全面了解
2016/07/13 Javascript
老生常谈Javascript中的原型和this指针
2016/10/09 Javascript
domReady的实现案例
2016/11/23 Javascript
Angular多选、全选、批量选择操作实例代码
2017/03/10 Javascript
jQuery阻止移动端遮罩层后页面滚动
2017/03/15 Javascript
基于代数方程库Algebra.js解二元一次方程功能示例
2017/06/09 Javascript
BootStrap TreeView使用实例详解
2017/11/01 Javascript
基于node打包可执行文件工具_Pkg使用心得分享
2018/01/24 Javascript
解决vue的变量在settimeout内部效果失效的问题
2018/08/30 Javascript
新手必须知的Node.js 4个JavaScript基本概念
2018/09/16 Javascript
使用Vue 实现滑动验证码功能
2019/06/27 Javascript
js实现提交前对列表数据的增删改查
2020/01/16 Javascript
javascript实现前端分页效果
2020/06/24 Javascript
python使用multiprocessing模块实现带回调函数的异步调用方法
2015/04/18 Python
打包发布Python模块的方法详解
2016/09/18 Python
python操作 hbase 数据的方法
2016/12/18 Python
Python入门_浅谈for循环、while循环
2017/05/16 Python
Python序列化基础知识(json/pickle)
2017/10/19 Python
python实现邮件自动发送
2019/08/10 Python
pytho matplotlib工具栏源码探析一之禁用工具栏、默认工具栏和工具栏管理器三种模式的差异
2021/02/25 Python
美国购买体育赛事门票网站:TicketCity
2019/03/06 全球购物
商务日语专业毕业生求职信
2013/10/26 职场文书
酒店采购员岗位职责
2014/03/14 职场文书
职称评定自我鉴定
2014/03/18 职场文书
工作推荐信范文
2014/05/10 职场文书
幼儿园庆元旦主持词
2015/07/06 职场文书
基于Redis zSet实现滑动窗口对短信进行防刷限流的问题
2022/02/12 Redis