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中shutil模块的学习笔记教程
Apr 04 Python
Django模板变量如何传递给外部js调用的方法小结
Jul 24 Python
python matplotlib画图实例代码分享
Dec 27 Python
python3解析库pyquery的深入讲解
Jun 26 Python
对python 数据处理中的LabelEncoder 和 OneHotEncoder详解
Jul 11 Python
基于python实现聊天室程序
Jul 27 Python
python读取csv文件指定行的2种方法详解
Feb 13 Python
浅谈python中频繁的print到底能浪费多长时间
Feb 21 Python
python实现PDF中表格转化为Excel的方法
Jun 16 Python
Lombok插件安装(IDEA)及配置jar包使用详解
Nov 04 Python
Python还能这么玩之用Python修改了班花的开机密码
Jun 04 Python
总结Python使用过程中的bug
Jun 18 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模板类代码
2008/09/07 PHP
php获取url字符串截取路径的文件名和扩展名的函数
2010/01/22 PHP
PHP 数组遍历方法大全(foreach,list,each)
2010/06/30 PHP
php array_unique之后json_encode需要注意
2011/01/02 PHP
php 数组的一个悲剧?
2011/05/11 PHP
解析:php调用MsSQL存储过程使用内置RETVAL获取过程中的return值
2013/07/03 PHP
CI(CodeIgniter)框架中的增删改查操作
2014/06/10 PHP
php获取、检查类名、函数名、方法名的函数方法
2015/06/25 PHP
UPUPW 更新 64 位 Apache 系列 PHP 7.0 正式版
2015/12/08 PHP
实例讲解PHP设计模式编程中的简单工厂模式
2016/02/29 PHP
php面试实现反射注入的详细方法
2019/09/30 PHP
JQuery 返回布尔值Is()条件判断方法代码
2012/05/14 Javascript
改变隐藏的input中value的值代码
2013/12/30 Javascript
浅谈JavaScript字符集
2014/05/22 Javascript
详解Javascript数据类型的转换规则
2016/12/12 Javascript
微信小程序 使用腾讯地图SDK详解及实现步骤
2017/02/28 Javascript
AngularJS实现的省市二级联动功能示例【可对选项实现增删】
2017/10/26 Javascript
jQuery 实现左右两侧菜单添加、移除功能
2018/01/02 jQuery
解决Layui 表单提交数据为空的问题
2018/08/15 Javascript
vue-cli3.0配置及使用注意事项详解
2018/09/05 Javascript
vue项目中使用tinymce编辑器的步骤详解
2018/09/11 Javascript
vue新建项目并配置标准路由过程解析
2019/12/09 Javascript
小程序自定义导航栏兼容适配所有机型(附完整案例)
2020/04/26 Javascript
JS数组push、unshift、pop、shift方法的实现与使用方法示例
2020/04/29 Javascript
Node.js中的异步生成器与异步迭代详解
2021/01/31 Javascript
[00:47]TI7不朽珍藏III——沙王不朽展示
2017/07/15 DOTA
[06:53]2018DOTA2国际邀请赛寻真——勇于创新的Vici Gaming
2018/08/14 DOTA
python根据给定文件返回文件名和扩展名的方法
2015/03/27 Python
python使用多线程编写tcp客户端程序
2019/09/02 Python
python 还原梯度下降算法实现一维线性回归
2020/10/22 Python
详解css3 object-fit属性
2018/07/27 HTML / CSS
南京迈特望C/C++面试题
2012/07/09 面试题
数控加工专业毕业生自荐信
2013/09/27 职场文书
2015年司机年终工作总结
2015/05/14 职场文书
严以用权学习心得体会
2016/01/12 职场文书
Java使用httpRequest+Jsoup爬取红蓝球号码
2021/07/02 Java/Android