尝试2to3工具
简单尝试2to3工具,不是很完美,如下
-import thread
+import _thread
-return [v for k, v in cls.socket_ket_map.items()]
+return [v for k, v in list(cls.socket_ket_map.items())]
-print(r.content)
+print((r.content))
3to2工具,更是不能接受,如下
b"- socket_file = conf.get('socket')"
b"+ socket_file = conf.get(u'socket')"
b'- print(r.content)'
b'+ print r.content'
2to3 底层是包含很多fixer,例如名为print的fixer负责处理由print语句到print函数的转换,可以启用或禁用特定的fixer(–fix–nofix)。
一个基于多个文件引用的项目,使用2to3并不能奏效。
使用six模块
six的逻辑是兼容python2.6+和python3,同样的代码可以在两种环境中执行。原理是为python2和python3变更的元素提供唯一接口。
字符串
Python3最大的变更是字符串类型为Unicode而不再是ASCII. python2可以通过from __future__ import unicode_literals
导入改行为, 如果编写兼容两个环境下运行的代码, 这是很好的方案.
python2的unicode类与python3的str类是同一个类,six.text_type
比对项 | python2 | python3 | six |
---|---|---|---|
文本字符串 | unicode类 | str类 | six.text_type |
字节字符串 | str类 | bytes类 | six.binary_type |
python2声明的字符串是utf-8类型 type
a = ‘abc’
type(type(a)) ⇒ type
比对项 | python2 | python3 |
---|---|---|
type(a) | str类 | str类 |
字符串类型 | 字节字符串 | 文本字符串 |
编码 | utf-8 | unicode |
type(a) == str | True | True |
type(a) == ‘str’ | False | False |
type(a) == six.text_type | False | True |
python3
In [1]: import six
In [2]: six.text_type
Out[2]: str
In [3]: type('ss') == six.text_type
Out[3]: True
In [4]: type(six.text_type('哈哈'))
Out[4]: str
In [5]: type('ss')
Out[5]: str
python2 print可以使用()但并不支持print的参数(end,sep等), 需要使用from __future__ import print_function
来完全支持python3的print
python2: print(1,2,3) ⇒ (1, 2, 3)
python3: print(1,2,3) ⇒ 1 2 3
除法
python3 int/int ⇒ float
python2 int/int ⇒ int
from __future__ import division
绝对与相对导入
python2在import foo
时实际发生:
- 解释器尝试在标准库中导入(json\six\sys等, pandas不在标准库)
- 找不到尝试相对导入(在导入模块的同一个目录中寻找名称为
foo.py
或者foo/__init__.py
的模块), 如果找到则完成; 如果找不到找不到尝试相对导入(在导入模块的同一个目录中寻找名称为foo.py
或者foo/__init__.py
的模块), 如果找到则完成 - 如果找不到, 他会开始在
sys.path
中的所有目录下寻找一个匹配的模块(绝对导入)
python3尽可能的移除相对导入, import foo
优先局对导入,后相对导入. 强制相对导入使用 import .foo
, 引入上一层目录foo
用import ..foo
python2使用from __future__ import absolute_import
引入python3的行为
被不推荐的类
异常
python2 raise ValueError, 'Invalid value.'
或raise ValueError('Invalid value.')
python3 raise ValueError('Invalid value.')
python2:
try:
raise ValueError('Invalid value.')
except ValueError, e:
print('%s' % e)
python3 python2.6+
try:
raise ValueError('Invalid value.')
except ValueError as e:
print('%s' % e)
python3增加了异常链
dict的方法
python2:
keys | values | items | return | note |
---|---|---|---|---|
keys() | values() | items() | list | 生成内存副本 |
iterkeys() | itervalues() | iteritems() | generator | 生成器 |
viewkeys() | viewvalues() | viewitems() | 生成器视图 | 视图对象仅仅引用原始字典, 如果原始字典改变, 视图会随之改变 |
python3 仅保留python2的生成器视图, 并将方法名改为 keys() | values() | items()
six
模块提供的 six.viewkeys() six.viewvalues() six.viewitems()
会用合适的方法法相匹配
迭代器
python2中, 迭代器期望一个无参的 next
方法, 在python3中, 它变为了__next__
.
如果需要一个在python2和python3中都能正确运行的迭代器, 正确的方案是
class DemoIterator(object):
def next(self):
return self.__next__()
任何继承DemoIterator的子类都能收到一个next
方法.
six
有一个six.Iterator
类, 没试过.
标准库重定位
six提供了获取正确模块的唯一接口 six.moves
涉及的模块有:
python2中import StringIO
和 from cStringIO import StringIO
两个模块
python3中只有from io import StringIO
six中 from six.moves.cStringIO import StringIO
python2中有 pickle
和 cPickle
模块
python3中只有 pickle
模块
six中 from six.moves import cPickle as pickle
python2中有urllib
urllib2
urlparse
三个模块
python3中都合并到了urllib
模块,
大多来自urlparse
模块(读取url并将其分解为单独部分)的方法位于 urllib.parse
; 很多关于解析的方法(比如quote
和unquote
)从urllib
移到了urllib.parse
python3中urllib
模块包含4个子模块:error
parse
request
response
, six.moves.urllib
模块同样为4个子模块,与python3行为一致.
重命名内置函数
python版本检测
six.PY2
six.PY3
返回bool值
sys.version_info.major
返回int值2\3
还有一些包被重组, 部分没有被six收录
six支持自己增加兼容模块
six.add_move(MovedModule('six中的名称', 'py2名称', 'py3名称'))
遇到的问题
python3调用一些数据模块默认返回utf8, 使用参数后可以返回unicode
json
模块 在python3.5及以下不能自动转换utf8\utf16, python3.6+能自动转换utf8
subprocess
模块universal_newlines=True
参数能自动转unicode, \n换行, python2和python3兼容, python3.6增加了encode
属性 python3.7增加了text
属性
redis
模块 redis.StrictRedis(host='127.0.0.1', port=6379, db=0, decode_responses=True)
decode_responses
属性会自动转
request
模块的 resp.context
返回的是二进制(bytes), resp.text模块返回的是str
request模块+gzip模块+BytesIO模块+StringIO模块
import six
if six.PY3:
def gzdecode(data):
buf = BytesIO(data)
gziper = gzip.GzipFile(mode='rb', fileobj=buf)
return gziper.read()
else:
def gzdecode(data):
buf = StringIO(data)
gziper = gzip.GzipFile(mode='rb', fileobj=buf)
return gziper.read()
gzdecode(resp.context)
一个字符串转换思路 py23 :
# -*- coding: utf-8 -*-
import six
import base64
import hmac
import hashlib
import gzip
if six.PY3:
from urllib.parse import urlencode, quote, unquote
from urllib.request import urlopen
from io import StringIO, BytesIO
import _thread as thread
def b(data):
if isinstance(data, str):
return data.encode('utf-8')
return data
def s(data):
if isinstance(data, bytes):
data = data.decode('utf-8')
return data
def u(data):
if isinstance(data, bytes):
data = data.decode('utf-8')
return data
else:
from urllib import urlencode, quote, unquote
from urllib2 import urlopen
from cStringIO import StringIO
import thread
def b(data):
return bytes(data)
def s(data):
return bytes(data)
def u(data):
if isinstance(data, str):
data = data.decode('utf-8')
return data
注释问题, python2不报错, python3报错(python2自动做了一些转换吧)
@App.route("/win_server/run_cmd", methods=["POST"])
def win_server_run_cmd():
"""
example:
1. 更新并重启 ae_pr_worker/monitor_ae
cmd=cd C:\Users\Administrator\wx_video;git pull;pm2 restart ae_pr_worker/monitor_ae
:return:
2. 重启shutdown -r -t 0
:return:
"""
cmd = request.get_json().get('cmd')
cmds = cmd.split(';')
ret = []
for _cmd in cmds:
print(_cmd)
return_code = subprocess.call(_cmd, shell=True)
ret.append({
'cmd': _cmd,
'return_code': return_code,
})
return jsonify(state=200, data=dict(msg='success', ret=ret))
python3报错如下:
File "run_server.py", line 407
"""
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 109-110: truncated \UXXXXXXXX escape
python3会解析反斜杠, 改为C:/Users/Administrator/wx_video, 或者在注释前加r, r""“note”""
参考: https://blog.csdn.net/u011242657/article/details/64437612