快乐的迁移到 Python3

2018 年 3 月 25 日 Python程序员

Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发。

为数据科学家提供的 Python3 特性简述

在机器学习和其他需大批量操作数据的科学领域,Python 已经成为了一门主流语言.它拥有各种深度学习框架和一系列完善的数据处理和可视化工具.

然而,Python 体系中 Python2 和 Python3 共存,而且很多数据科学家仍然在使用 Python2.到2019年底,科学栈将停止支持 Python2.至于 numpy,2018年以后的所有新版本将只支持 Python3.

为了让过渡更轻松一些,我整理了一些 Python3 你可能觉得有用的特性.

图片来自Dario Bertini post (toptal)

使用 pathlib 更好的处理路径

pathlib 是 Python3的一个默认模块,有助于避免大量使用 os.path.join

之前,人们倾向于使用字符串连接(简洁,但明显不好). 现在,使用 pathlib 之后,代码更加安全,简洁,可读性强.

另外 pathlib.Path 还有大量的方法和属性,每个 python 初学者在早期都需要通过 Google 来了解:

pathlib 应该会为你节省大量时间,请参阅文档参考资料以获取更多信息.

类型提示现在已经是语言的一部分

pycharm 中类型提示的例子:

Python 已不再是一个小的脚本语言了,现如今,数据管道包含了不同的级别,每个级别又涉及到不同的框架(有时会有千差万别的逻辑).

引入类型提示是为了应对日益增加的程序复杂性,这样机器能够对代码进行辅助验证.以前不同的模块使用自定义的方式来在文档字符串中指明变量的类型)(提示:pycharm 可以将旧的文档字符串转换为新的类型提示).

举一个简单的例子,下面的代码适用于不同的数据类型(这也是我们喜欢 python 数据栈的地方)

这段代码可适用于 numpy.array(包含多维的), astropy.Tableastropy.Column, bcolz, cupy, mxnet.ndarray 和其他组件.

这段代码虽然也适用于 pandas.Series, 但却是错误的使用方式:

这只是两行代码而已.设想一下仅仅一个函数运行不当,会导致一个复杂系统有多少不可预知的行为.在一个大型系统中,明确指出方法所需的类型是非常有帮助的.如果给函数传递了异常参数,它会给出警告.

如果你有一个重要的代码库,像 MyPy 这样的提示工具很可能会成为你持续集成管道的一部分. Daniel Pyrathon 主持的"Putting Type Hints to Work"网络研讨会是一个很好的简介.

旁注:不幸的是,提示信息还不能强大到为 ndarrays/tensors 提供细粒度的类型支持,可终将会实现,这也将成为 DS 的一大特色.

类型提示→运行期类型检查

默认情况下,函数注释并不会影响你代码的运行方式,它仅仅会帮助你指出代码的意图.

然而,你可以使用类似 enforce 这样的工具在代码运行期进行类型检查,这对你进行 debug 是很有帮助的(很多情况下,类型提示并不生效).

函数注释的其他用途

如前文所述, 注释对代码运行没有影响,只是提供了一些元信息,你可以随意使用.

例如, 测量单位是科学领域常见的痛点, astropy提供了一个简单的装饰器来控制输入数量的单位并转换为输出部分所需的单位.

如果你正在用 python 处理表格式的科学数据(没必要是天文数字), 你可以尝试一下 astropy.

你也可以自定义专用的装饰器,以同样的方式来执行输入和输出的控制/转换.

矩阵乘法 @

让我们来实现一个最简单的 ML 模型 — 一个具有 l2正则化的线性回归(又名岭回归)

使用@后的代码在深度学习框架之间更有可读性和可转换性:对于单层感知器, 相同的代码X @ W + b[None, :] 都可运行于 numpy, cupy, pytorch, tensorflow (以及其他基于张量运行的框架)

通配符 **

在 Python2 中递归文件夹通配并不容易,即使 glob2 的自定义模块已经解决了这个问题.自 Python 3.5以来便支持了递归标识:

一个更好的选择是在 python3 中使用 pathlib(减少了一个导入!):

注意:在 glob.glob, Path.glob 和 bash 通配符之间有些微不同.

Print 现在是一个函数

代码中虽然多了一些烦人的括号,但也有一些好处:

  • 简化了使用文件描述符的语法

  • 不使用 str.join 打印制表符对齐表:

  • 结束/重定向打印输出:

    在 jupyter 中,最好将每个输出记录到一个单独的文件中(以便追踪断开连接后发生的情况),现在ni 可以重写 print 了.

    下面是一个暂时覆盖打印行为的上下文管理器:

并不推荐这种方法,但却是现在能接受的一个非常规的解决方式.

  • print 可以加入列表推导和其他语言结构

数字中的下划线(千位分隔符)

PEP-515 在数字中引入了下划线.在 Python3 中,下划线可用于在整数,浮点数以及复杂数字中以可视化的方式对数字进行分组.

用于简单可靠格式化的 f-strings

默认的格式化系统提供了数据实验中不必要的灵活性.由此产生的代码对于任何修改都显得太冗余和太脆弱.通常数据科学家会以一种固定格式反复输出一些日志信息.如下代码就是常见的一段:

例子输出:

Python3.6 引入了格式化字符串 f-strings:

true 除法 和 floor 除法的明显区别

对于数据科学来说,这绝对是一个便利的改变

Python2 中的结果取决于 "time" 和 "distance"(以米和秒计量)是否存储为整数.而在 Python3 中,因为除法的计算结果是浮点数,因此在两种情况下结果都是正确的.

另外一种情况是 floor 除法,现在可以精确运算了:

简言之:

注意:这都适用于内置类型和数据包提供的自定义类型(如 numpypandas)

严格排序

  • 防止偶尔对不同类型的实例进行排序

  • 有助于发现处理原始数据时出现的一些问题

旁注:合理检查 None (两个 Python 版本中都有)

用于 NLP(神经语言程序学 Neuro-Linguistic Programming) 的 Unicode

输出:

  • Python 2: 6

  • Python 3: 2 您好

Python2 失败了, Python3 符合预期(因为我在字符串中使用了俄文)

在 Python3 中,str 是 unicode 字符串, 对于非英文文本的 NLP 处理更为方便.

还有一些有趣的东西,比如:

  • Python 2: Counter({"Ã": 2, "b": 1, "e": 1, "c": 1, "k": 1, "M": 1, "l": 1, "s": 1, "t": 1, "¶": 1, "¼": 1})

  • Python 3: Counter({"M": 1, "ö": 1, "b": 1, "e": 1, "l": 1, "s": 1, "t": 1, "ü": 1, "c": 1, "k": 1})

虽然在 Python2 中你可以正确的处理这一切,但 Python3 显得更加友好.

保持字典和 **kwargs 的顺序

在 CPython 3.6+ 中,字典的默认行为与 OrderedDict 类似(并且在 Python 3.7+ 中也已经得到保证),这样在字典推导时保持了顺序(还有一些其他操作,比如: json 的序列化/反序列化)

同样适用于 **kwargs (Python 3.6+),他们会保持跟传参时一样的顺序.顺序对于数据管道来说至关重要,但以前我们只能以繁琐的方式来编写:

你注意到了吗?名字的唯一性也会自动检查.

可迭代对象的解压

默认的 pickle 引擎为数组提供更好的压缩

Pickling 是线程/进程间传输数据的一种机制, 特别应用在多处理包中.

只用了1/3的空间,并且快了很多.实际上设置参数protocol=2也可以实现类似的压缩操作(速度不会这么快),但开发者们一般都会忽略这个选项(或者根本不知道有这个选项).

注意: pickle 并不安全(且非常不好转换), 所以在接收到不信任或者未经证实的数据后,不要 unpickle 这些数据.

更安全的推导式

超简单的 super() 函数

Python2中的 super(...) 曾是代码中最常见的错误源.

stackoverflow 上有更多关于 super 和 MRO(方法解析顺序)的信息。

IDE 提供了更好的变量注释建议

在 Java, C#以及其他类似语言编程过程中,最享受的事情就是 IDE 可以给出很好的建议, 这是因为程序运行前每个标识符的类型都是已知的.

在 Python 中这很难实现, 但注释可以提供一些帮助

  • 用清晰的格式写下期望的类型

  • 从 IDE 中获取到好的建议 

这是 PyCharm 中带有变量注释的建议示例。即使在使用的函数没有注释的情况下,依旧有效(取决于向后的兼容性).

多重 unpacking

现在展示如何合并两个字典:

请参照在 StackOverflow 中的这一过程, 与 Python2 做个比较.

对 lists, tuples 和 sets(a, b, c 是可任意迭代的), 此方法同样有效:

同样支持函数中的 *args**kwargs 参数:

具有关键字参数的面向未来的 API

让我们看一下这段代码:

显然, 代码作者并不了解 Python 的编码风格(很有可能是从 app 或者 rust 转到 Python 的).不幸的是, 这还不仅仅是一个品位的问题, 因为在 SVC 中改变参数的顺序(添加/删除)会破坏这段代码. 尤其是 为了提供一致性的 API, sklearn 会时不时的对大量算法参数做重排序/重命名操作, 每个这样的重构都有可能会破坏代码.

在 Python3中, 类库作者通过使用 * 来要求明确命名参数:

  • 用户现在必须指定参数名称为 sklearn.svm.SVC(C=2, kernel="poly", degree=2, gamma=4, coef0=0.5)

  • 这种机制提供了 API 完美结合的可靠性和灵活性

次要:math 模块中的常量

次要:单一的整数类型

Python2 提供了两种基本整数类型: int(64位有符号整数)和针对长整型计算的long(从C++之后就变得非常混乱)

Python3 只有一个单一的 int 类型, 同时融合了长整型计算.

以下展示了如何校验一个值是整数:

其他事项

  • Enum 理论上很有用, 但是

    • string-typing 在 python 数据栈中已经广泛被采用了

    • Enum 似乎不会与 numpy 以及 pandas categorical 相互作用

  • coroutines 在数据管道中的前景看似光明(参看David Beazley的幻灯片),但我并没有看到他们被更广泛的采用.

  • Python3 有稳定的 ABI(Application Binary Interface: 应用程序二进制接口 描述了应用程序和操作系统之间,一个应用和它的库之间,或者应用的组成部分之间的低接口)

  • Python3 支持 unicode 标识(甚至 ω = Δφ / Δt 也可以), 但最好还是使用旧的ASCII名称

  • 一些类库如 jupyterhub(云端jupyter), django 和最新的 ipython 只支持 Python3, 因此一些你听起来无用的功能,对于你可能使用的类库却很有用.

具体的数据科学的代码迁移问题(以及如何解决这些问题)

  • 不再支持嵌套参数 

但是,仍然完全适用于不同的(列表)解析: 

  • 一般来说, 从 Python2 到 Python3之间的解析也有着更好的"可翻译性".

  • map(), .keys(), .values(), .items() 等返回的是迭代器(iterators),而不是列表(lists). 迭代器的主要问题如下:

    • 没有细小的切片

    • 不能迭代两次

  • 几乎所有问题在转化为列表后都可以解决

  • 遇到问题时可以参考Python 帮助:如何迁移到 Python3?

机器学习和数据科学 Python 教学中的主要问题

课程作者应该花时间在第一讲中解释清楚什么是迭代器,为什么它不能像字符串一样被分割/连接/相乘/迭代两次(以及如何处理这个问题).

我想大多数课程作者都曾很乐于避开这些细节, 但现在几乎不可能了.

结论

虽然 Python2 和 Python3 已经共存快10年了, 但我们还是应该迁移到 Python3.

转向使用唯一的 Python3 代码库之后, 科研和生产代码应该会更简洁, 更有可读性, 更安全.

目前大部分类库都支持两个 Python 版本. 我已迫不及待的等待依赖包们放弃 Python2,享受新语言特性的那个光明时刻.

后续的迁移会更加顺畅:"我们再也不想做这种不向后兼容的变化了".


英文原文:https://github.com/arogozhnikov/python3_with_pleasure
译者:郭明


登录查看更多
5

相关内容

Python是一种面向对象的解释型计算机程序设计语言,在设计中注重代码的可读性,同时也是一种功能强大的通用型语言。
专知会员服务
165+阅读 · 2020年6月4日
【实用书】Python技术手册,第三版767页pdf
专知会员服务
228+阅读 · 2020年5月21日
机器学习速查手册,135页pdf
专知会员服务
335+阅读 · 2020年3月15日
【书籍推荐】简洁的Python编程(Clean Python),附274页pdf
专知会员服务
173+阅读 · 2020年1月1日
Python 3.8.0来了!
数据派THU
5+阅读 · 2019年10月22日
抖音爬虫
专知
3+阅读 · 2019年2月11日
Python3.7中一种懒加载的方式
Python程序员
3+阅读 · 2018年4月27日
Python 杠上 Java、C/C++,赢面有几成?
CSDN
6+阅读 · 2018年4月12日
为什么你应该学 Python ?
计算机与网络安全
4+阅读 · 2018年3月24日
推荐|2017年最受数据科学欢迎的Top15个Python库!
全球人工智能
8+阅读 · 2017年10月28日
Python3爬虫之入门和正则表达式
全球人工智能
7+阅读 · 2017年10月9日
Python 书单:从入门到……
Linux中国
38+阅读 · 2017年8月6日
Arxiv
24+阅读 · 2020年3月11日
Arxiv
91+阅读 · 2020年2月28日
A Comprehensive Survey on Transfer Learning
Arxiv
117+阅读 · 2019年11月7日
Deep Co-Training for Semi-Supervised Image Segmentation
Factor Graph Attention
Arxiv
6+阅读 · 2019年4月11日
Arxiv
7+阅读 · 2018年4月21日
VIP会员
相关VIP内容
专知会员服务
165+阅读 · 2020年6月4日
【实用书】Python技术手册,第三版767页pdf
专知会员服务
228+阅读 · 2020年5月21日
机器学习速查手册,135页pdf
专知会员服务
335+阅读 · 2020年3月15日
【书籍推荐】简洁的Python编程(Clean Python),附274页pdf
专知会员服务
173+阅读 · 2020年1月1日
相关资讯
Python 3.8.0来了!
数据派THU
5+阅读 · 2019年10月22日
抖音爬虫
专知
3+阅读 · 2019年2月11日
Python3.7中一种懒加载的方式
Python程序员
3+阅读 · 2018年4月27日
Python 杠上 Java、C/C++,赢面有几成?
CSDN
6+阅读 · 2018年4月12日
为什么你应该学 Python ?
计算机与网络安全
4+阅读 · 2018年3月24日
推荐|2017年最受数据科学欢迎的Top15个Python库!
全球人工智能
8+阅读 · 2017年10月28日
Python3爬虫之入门和正则表达式
全球人工智能
7+阅读 · 2017年10月9日
Python 书单:从入门到……
Linux中国
38+阅读 · 2017年8月6日
相关论文
Top
微信扫码咨询专知VIP会员