• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >python > 把项目从Python2.x移植到Python3.x的经验总结

把项目从Python2.x移植到Python3.x的经验总结

作者:goldensun 字体:[增加 减小] 来源:互联网

goldensun 通过本文主要向大家介绍了python2.x,python2.x下载,python2.x和3.x,python2.x和3.x区别,项目经验等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

 经历移植jinja2到python3的痛苦之后,我把项目暂时放一放,因为我怕打破python3的兼容。我的做法是只用一个python2的代码库,然后在安装的时候用2to3工具翻译成python3。不幸的是哪怕一点点的改动都会打破迭代开发。如果你选对了python的版本,你可以专心做事,幸运的避免了这个问题。

来自MoinMoin项目的Thomas Waldmann通过我的python-modernize跑jinja2,并且统一了代码库,能同时跑python2,6,2,7和3.3。只需小小清理,我们的代码就很清晰,还能跑在所有的python版本上,并且看起来和普通的python代码并无区别。

受到他的启发,我一遍又一遍的阅读代码,并开始合并其他代码来享受统一的代码库带给我的快感。

下面我分享一些小窍门,可以达到和我类似的体验。

放弃python 2.5 3.1和3.2

这是最重要的一点,放弃2.5比较容易,因为现在基本没人用了,放弃3.1和3.2也没太大问题,应为目前python3用的人实在是少得可怜。但是你为什么放弃这几个版本呢?答案就是2.6和3.3有很多交叉哦语法和特性,代码可以兼容这两个版本。

  •     字符串兼容。2.6和3.3支持相同的字符串语法。你可以用 "foo" 表示原生字符串(2.x表示byte,3.x表示unicode),u"foo" 表示unicode字符串,b"foo" 表示原生字符串或字节数组。
  •     print函数兼容,如果你的print语句比较少,那你可以加上"from __future__ import print_function",然后开始使用print函数,而不是把它绑定到别的变量上,进而避免诡异的麻烦。
  •     兼容的异常语法。Python 2.6引入的 "except Exception as e" 语法也是3.x的异常捕捉语法。
  •     类修饰器都有效。这个可以用在修改接口而不在类结构定义中留下痕迹。例如可以修改迭代方法名字,也就是把 next 改成 __next__ 或者把 __str__ 改成 __unicode__ 来兼容python 2.x。
  •     内置next调用__next__或next。这点很有用,因为他们和直接调用方法的速度差不多,所以你不用考虑得太多而去加入运行时检查和包装一个函数。
  •     Python 2.6 加入了和python 3.3接口一样的bytearray类型。这点也很有用,因为2.6没有 3.3的byteobject类型,虽然有一个内建的名字但那仅仅只是str的别名,并且使用习惯也有很大差异。
  •     Python 3.3又加入了byte到byte和string到string的编码与解码,这已经在3.1和3.2中去掉了,很不幸,他们的接口很复杂了,别名也没了,但至少更比以前的2.x版本更接近了。

最后一点在流编码和解码的时候很有用,这功能在3.0的时候去掉了,直到3.3才恢复。


没错,six模块可以让你走得远一点,但是不要低估了代码工整度的意义。在Python3移植过程中,我几乎对jinja2失去了兴趣,因为代码开始虐我。就算能统一代码库,但还是看起来很不舒服,影响视觉(six.b('foo')和six.u('foo')到处飞)还会因为用2to3迭代开发带来不必要的麻烦。不用去处理这些麻烦,回到编码的快乐享受中吧。jinja2现在的代码非常清晰,你也不用当心python2和3的兼容问题,不过还是有一些地方使用了这样的语句:if PY2:。

接下来假设这些就是你想支持的python版本,试图支持python2.5,这是一个痛苦的事情,我强烈建议你放弃吧。支持3.2还有一点点可能,如果你能在把函数调用时把字符串都包装起来,考虑到审美和性能,我不推荐这么做。

跳过six

six是个好东西,jinja2开始也在用,不过最后却不给力了,因为移植到python3的确需要它,但还是有一些特性丢失了。你的确需要six,如果你想同时支持python2.5,但从2.6开始就没必要使用six了,jinja2搞了一个包含助手的兼容模块。包括很少的非python3 代码,整个兼容模块不足80行。

因为其他库或者项目依赖库的原因,用户希望你能支持不同版本,这是six的确能为你省去很多麻烦。

开始使用Modernize

使用python-modernize移植python是个很好的还头,他像2to3一样运行的时候生成代码。当然,他还有很多bug,默认选项也不是很合理,可以避免一些烦人的事情,然你走的更远。但是你也需要检查一下结果,去掉一些import 语句和不和谐的东西。
修复测试

做其他事之前先跑一下测试,保证测试还能通过。python3.0和3.1的标准库就有很多问题是诡异的测试习惯改变引起的。

写一个兼容的模块

因此你将打算跳过six,你能够完全抛离帮助文档么?答案当然是否定的。你依然需要一个小的兼容模块,但是它足够小,使得你能够将它仅仅放在你的包中,下面是一个基本的例子,关于一个兼容模块看起来是个什么样子:
 

import sys
PY2 = sys.version_info[0] == 2
if not PY2:
 text_type = str
 string_types = (str,)
 unichr = chr
else:
 text_type = unicode
 string_types = (str, unicode)
 unichr = unichr
</div>

那个模块确切的内容依赖于,对于你有多少实际的改变。在Jinja2中,我在这里放了一堆的函数。它包括ifilter, imap以及类似itertools的函数,这些函数都内置在3.x中。(我纠缠Python 2.x函数,是为了让读者能够对代码更清楚,迭代器行为是内置的而不是缺陷) 。

为2.x版本做测试而不是3.x

总体上来说你现在正在使用的python是2.x版本的还是3.x版本的是需要检查的。在这种情况下我推荐你检查当前版本是否是python2而把python3放到另外一个判断的分支里。这样等python4面世的时候你收到的“惊喜”对你的影响会小一点

好的处理:
 

if PY2:
 def __str__(self):
  return self.__unicode__().encode('utf-8')
</div>

相比之下差强人意的处理:

 

if not PY3:
 def __str__(self):
  return self.__unicode__().encode('utf-8')
</div>

字符串处理
Python 3的最大变化毫无疑问是对Unicode接口的更改。不幸的是,这些更改在某些地方非常的痛苦,而且在整个标准库中还得到了不一致地处理。大多数与字符串处理相关的时间函数的移植将完全被废止。字符串处理这个主题本身就可以写成完整的文档,不过这儿有移植Jinja2和Werkzeug所遵循的简洁小抄:

    'foo'这种形式的字符串总指的是本机字符串。这种字符串可以用在标识符里、源代码里、文件名里和其他底层的函数里。另外,在2.x里,只要限制这种字符串仅仅可使用ASCII字符,那么就允许作为Unicode字符串常量。
    这个属性对统一编码基础是非常有用的,因为Python 3的正常方向时把Unicode引进到以前不支持Unicode的某些接口,不过反过来却从不是这样的。由于这种字符串常量“升级”为Unicode,而2.x仍然在某种程度上支持Unicode,因此这种字符串常量怎么用都行。
    例如 datetime.strftime函数在Python2里严格不支持Unicode,并且只在3.x里支持Unicode。不过因为大多数情况下2.x上的返回值只是ASCII编码,所以像这样的函数在2.x和3.x上都确实运行良好。
   

 >>> u'<p>Current time: %s' % datetime.datetime.utcnow().strftime('%H:%M')
 u'<p>Current time: 23:52'
</div>

    传递给strftime的字符串是本机字符串(在2.x里是字节,而在3.0里是Unicode)。返回值也是本机字符串并且仅仅是ASCII编码字符。 因此在2.x和3.x上一旦对字符串进行格式化,那么结果就一定是Unicode字符串。
    u'foo'这种形式的字符串总指的是Unicode字符串,2.x的许多库都已经有非常好的支持Unicode,因此这样的字符串常量对许多人来说都不应该感到奇怪。

    b'foo'这种形式的字符串总指的是只以字节形式存储的字符串。由于2.6确实没有类似Python 3.3所具有的字节对象,而且Python 3.3缺乏一个真正的字节字符串,因此这种常量的可用性确实受到小小的限制。当与在2.x和3.x上具有同样接口的字节数组对象绑定在一起时候,它立刻变得更可用了。
    由于这种字符串是可以更改的,因此对原始字节的更改是非常有效的,然后你再次通过使用inbytes()封装最终结果,从而转换结果为更易读的字符串。


除了这些基本的规则,我还对上面我的兼容模块添加了 text_type,unichr 和 string_types 等变量。通过这些有了大的变化:

  •     isinstance(x, basestring) 变成 isinstance(x, string_types).
  •     isinstance(x, unicode) 变成 isinstance(x, text_type).
  •     isinstance(x, str) 为表明捕捉字节的意图,现在变成 isinstance(x, bytes) 或者 isinstance(x, (bytes, bytearray)).

我还创建了一个 implements_to_string 装饰类,来帮助实现带有 __unicode__ 或

您可能想查找下面的文章:

  • Python2.x利用commands模块执行Linux shell命令
  • Python2.x利用commands模块执行Linux shell命令
  • Windows下使Python2.x版本的解释器与3.x共存的方法
  • Python2.x版本中基本的中文编码问题解决
  • Windows下使Python2.x版本的解释器与3.x共存的方法
  • Python2.x版本中基本的中文编码问题解决
  • Python2.x中文乱码问题解决方法
  • 简单介绍Python2.x版本中的cmp()方法的使用
  • Python2.x版本中maketrans()方法的使用介绍
  • Python2.x版本中cmp()方法的使用教程

相关文章

  • 分享一个常用的Python模拟登陆类
  • python获取本机外网ip的方法
  • Python实现Tab自动补全和历史命令管理的方法
  • 全面解读Python Web开发框架Django
  • Python的Twisted框架中使用Deferred对象来管理回调函数
  • python的random模块及加权随机算法的python实现方法
  • python使用psutil模块获取系统状态
  • Python的装饰器用法学习笔记
  • Windows系统下安装Python的SSH模块教程
  • Python 字典与字符串的互转实例

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • python中as用法实例分析
    • Python中下划线的使用方法
    • Python实例一个类背后发生了什么
    • 通过数据库向Django模型添加字段的示例
    • python基础教程之循环介绍
    • Python远程桌面协议RDPY安装使用介绍
    • Python中set与frozenset方法和区别详解
    • Python 登录网站详解及实例
    • python实现删除文件与目录的方法
    • python base64 decode incorrect padding错误解决方法

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有