python升级踩坑小记

python升级踩坑小记

最近在升级公司内部的测试平台,由python2.7升级到3.6,遇到一些问题以及解决方案和总结,在此简单mark一下:

一、首先就是最常见的语法及built-in问题

1、异常捕获

2、迭代器函数或方法

python2中range返回一个列表,xrange返回迭代器,py2的大部分文档或书籍都一直推荐使用xrange,节省内存,效率也不低。py3只有range-返回迭代器,说明了使用迭代器的优势。包括dict的iteritems方法也去掉了,直接使用items返回的就是迭代器。还有很多函数和方法都直接改为返回迭代器或是视图,在数据量很大的情况下,极大的节省了内存的使用。

3、print,py3中将print改为函数了。我一般在文件最低端的if __name__ == ‘__main__’中调试代码时,输出部分会用print,由于大部分文件都是作为库文件使用,所以没有刻意去掉该部分测试代码。 根本原因还是编程不规范造成,由单元测试代码替代可以完全避免解决该问题,也可保证代码质量。以此谨记!!!

4、编码问题:python2解释器在运行时内部默认使用的是ASCII编码,所以程序如果要输出非ASCII的字符则需要

而python3中默认的系统编码为utf-8,所以不需要修改,但是!!reload函数不再是built-in函数了,而是被放到imp标准库中了,所以运行上述代码肯定会报NameError。有人可能会说在文件头部声明#coding=utf-8不就可以了,不好意思,这不是同一个问题。

在python3版本中,如果需要用到reload则import imp;如果是编码问题,则去掉reload部分的代码即可;如果要py2和3兼容可以借助six库中的reload或者如下实现

5、除法问题

python2中整数间的除法返回整数或者0,传入其他函数,比如range是没有问题的,再或者给变量赋值a=2/5 or 1,此时a=1,而在py3中这两种情况都是不成立的

解决方案:如果需要以上需求,用int包裹除法部分即可,int是一刀切式取整,直接扔掉小数部分,所以a=int(2/5) or 1 在py2和3中都是成立的

二、数据结构

其实改语法 、改逻辑、改架构都还好,真正让人头疼的是修改数据结构,真心是牵一发动全身。python2中二进制数据和字符串是混用的,没有区分,可以简单的认为bytes == str,其实就是单纯的字符串,没有二进制的概念。python3中严格区分了这二者,二进制经过decode后是字符串,字符串encode后是二进制。例如:a=b”123″ python2中a[1]=b”2″;python3中a[1]=50,而且很多标准库的方法限定了参数类型只能是bytes或str,而python2中是不做区分的。

被测试的目标服务为C++实现,全部为TCP协议,交互使用二进制加密数据。测试框架中使用了AES加密方式,标准库struct来封装和解封数据包,每个服务的入参类型是需要既定的协议严格限定的,python2中封装字符串类型的直接给struct传个字符串或chr,但是python3中必须传bytes object,所以就导致了涉及到字符串的参数需要全部修改,包括动态传参和默认参数,每个服务都得手动修改,尤其的默认参数,然后挨个调试,可想而知,服务数量庞大的话,这个修改的代价也是很高的。

由于历史遗留问题,该部分代码设计的不是很合理,涉及到重构的参数没必要使用字符串或chr,使用相同位数的整型完全可以,而且也便于解析。只怪自己没有及时重构,给升级带来了不小的阻碍。冰冻三尺非一日之寒,其实很多问题一直存在,日积月累,像一颗定时炸弹,直到爆炸的那一天才警醒,如果平时在遇到时积极解决而不是逃避,也不会留下太多的小坑,最后变成大坑,追悔莫及。谨以此役,引以为戒!

三、第三方依赖库

测试平台采用的大部分第三方库都是热度较高社区活跃的,比如django,gevent等,对于python3都是兼容或者有独立的版本;个别轻度依赖的库直接修改源码或是抛弃自己重写即可,这方面在升级过程中没有太大阻碍

在升级移植方面,官档推荐了两个工具 Futurize 和 Modernize.  有需要可以参考。由于在升级前已经查阅了很多py2和3差异相关的文档,而且该测试框架的大部分代码都是自己写的,所以还是比较清楚在移植过程中存在的问题,就没有介入其他移植工具,一来是减少时间成本,再则是借助工具也不能全部完美转换,还是需要手动修改。不如直接review核心代码,手动修改,温故知新,顺便优化,皆大欢喜。

Comments are closed.