python2升级至python3


首先使用工具 2to3 转换

12to3 目录名 -w -n

print

https://stackoverflow.com/questions/55559825/how-to-fix-print-double-parentheses-after-2to3-conversion

  • 问题: 如果在python2项目里使用了python3的写法,比如在 python2 里的 print("test"), 使用 2to3 就会转换成

    1print(("test"))

    所以需要找到 print(( 并修复该转换(其实不转也没什么问题)

    1ag -Gpy 'print(('
  • 修复:

    1- print(("test"))
    2+ print("test")
    

string

  • 问题1:

    1module 'string' has no attribute 'letters
  • 修复:

    1- string.letters
    2+ string.ascii_letters
    
  • 问题2:

    1'str' object has no attribute 'decode'
  • 修复:

    1- str.decode(xxx)
    2+ str.encode(xxx).decode('unicode_escape')
    

比值问题

1slice indices must be integers or None or have an __index__ method
  • 问题: python2里 3/2 返回的是整型 1 python3里 3/2 返回的是浮点型 1.5

  • 修复:

    1print(3//2)
    2# 或者
    3print(int(3/2))

编码问题

sys.setdefaultencoding('utf-8')

python2里的 sys.setdefaultencoding('utf-8') 需要删除

encode、decode

  • 问题:

    1LookupError: 'base64' is not a text encoding; use codecs.encode() to handle arbitrary codecs
  • 语法:

    • python2

      1Python 2.7.16 (default, Dec 21 2020, 23:00:36)
      2[GCC Apple LLVM 12.0.0 (clang-1200.0.30.4) [+internal-os, ptrauth-isa=sign+stri on darwin
      3Type "help", "copyright", "credits" or "license" for more information.
      4>>> a = "a"
      5>>> a.encode("base64")
      6'YQ==\n'
      7>>> b = a.encode("base64")
      8>>> b.decode("base64")
      9'a'
    • python3

      1Python 3.7.4 (default, Sep  7 2020, 15:30:33)
      2[Clang 11.0.3 (clang-1103.0.32.29)] on darwin
      3Type "help", "copyright", "credits" or "license" for more information.
      4>>> a = "a"
      5>>> a.encode("base64")
      6Traceback (most recent call last):
      7  File "<stdin>", line 1, in <module>
      8LookupError: 'base64' is not a text encoding; use codecs.encode() to handle arbitrary codecs
  • 修复:

    1import base64
    2
    3def b64encode(s):
    4    if isinstance(s, bytes):
    5        return base64.b64encode(s)
    6    return base64.b64encode(s.encode('utf-8')).decode('utf-8')
    7
    8def b64decode(s):
    9    return base64.b64decode(s).decode('utf-8')
    1- x.encode('base64')
    2- x.decode('base64')
    3+ b64encode(x)
    4+ b64decode(x)
    

编码转换

utf-8转换为gbk

  • python2

    1'hello世界'.decode('utf-8').encode('gbk')
  • python3

    1''.join([chr(i) for i in 'hello世界'.encode('gbk')])
    2# 或者
    3'hello世界'.encode('gbk').decode('unicode_escape')

cmp

python3里cmp内置函数不再存在,需要自定义函数

1def cmp(a, b):
2    return (a > b) - (a < b)

sorted

python2里sorted有一个cmp参数,python3里统一为key参数

  • python2

    1sorted(keys, lambda x, y: cmp(len(x), len(y)), reverse=True)
  • python3

    1from functools import cmp_to_key
    2
    3sorted(keys, key=cmp_to_key(lambda x, y: cmp(len(x), len(y))), reverse=True)

    注意: must use keyword argument for key function

Exception

  • python3里没有 .message, 所以需要修改 e.messagestr(e)

  • python3无法使用 as 直接对变量赋值

     1def main():
     2    err = None
     3    try:
     4        raise ValueError("sss")
     5    -    except Exception as err:
     6    -       pass
     7    +    except Exception as e:
     8    +       err = e
     9    return err
    10
    11print(main())
    1UnboundLocalError: local variable 'err' referenced before assignment

SSL

  • 问题:

    1File "/usr/local/lib/python3.6/dist-packages/OpenSSL/SSL.py", line 1591, in set_tlsext_host_name
    2raise TypeError("name must be a byte string")
  • 解决

    1- s.set_tlsext_host_name(hostname)
    2+ s.set_tlsext_host_name(hostname.encode('utf-8'))

file.read

1with open("test.txt", "rb") as f:
2    for i in f.read(10):
3        print(i, type(i))
  • python2

    1('\x7f', <type 'str'>)
    2('E', <type 'str'>)
    3('\x00', <type 'str'>)
  • python3

    1127 <class 'int'>
    269 <class 'int'>
    30 <class 'int'>
  • 两者之间的转换

    1ord('\x7f') == 127
    2chr(127) == '\x7f'

redis

python3里默认取出的值是 bytes 类型, 需要客户端添加 decode_responses=True 参数, 取出的值才是 str 类型

requests

自定义编码请求

https://github.com/psf/requests/issues/4133

post json

  • python2

    1data = {'test': 'hello世界'.decode('utf-8').encode('gbk')}
    2headers = {'Content-Type': 'application/json;charset=gbk'}
    3data=json.dumps(data,ensure_ascii=False)
    4rsp = requests.post("/dynamic/test", data=data,headers=headers)
  • python3

    1data = {'test': 'hello世界'}
    2headers = {'Content-Type': 'application/json;charset=gbk'}
    3data=json.dumps(data, ensure_ascii=False)
    4resp = requests.post("/dynamic/test", data=data.encode('gbk'), headers=headers)

post form

  • python2

    1data = {'test': 'hello世界'.decode('utf-8').encode('gbk')}
    2headers = {'Content-Type': 'application/x-www-form-urlencoded;charset=gbk'}
    3resp = requests.post("/dynamic/test", data=data,headers=headers)
  • python3

    1data = {'test': 'hello世界'.encode('gbk')}
    2headers = {'Content-Type': 'application/x-www-form-urlencoded;charset=gbk'}
    3resp = requests.post("/dynamic/test", data=data,headers=headers)

响应编码

1resp = requests.get("...")
2print(type(resp.content))
3print(type(resp.text))
  • python2 resp.contentstr 类型, resp.textunicode 类型

  • python3 resp.contentbytes 类型, resp.textstr 类型

请求headers顺序

根源主要在 requests.structuresCaseInsensitiveDict

 1from requests.structures import CaseInsensitiveDict
 2from collections import OrderedDict
 3
 4headers = {
 5    'Accept-Language': 'en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4',
 6    'Accept-Encoding': 'gzip, deflate, sdch',
 7    'cache': 0,
 8    'host': 'Host1.com',
 9    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
10    'User-Agent': 'curl/7.29.0',
11    'Host': 'Host2.com'
12}
13print(headers)
14
15r = CaseInsensitiveDict()
16r.update(headers)
17print(r)

不同的python版本结果会输出

  • python2

    1OrderedDict([('Accept-Language', 'en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4'), ('Accept-Encoding', 'gzip, deflate, sdch'), ('cache', 0), ('Host', 'Host2.com'), ('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'), ('User-Agent', 'curl/7.29.0'), ('host', 'Host1.com')])
    2CaseInsensitiveDict({'Accept-Language': 'en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4', 'Accept-Encoding': 'gzip, deflate, sdch', 'cache': 0, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'User-Agent': 'curl/7.29.0', 'host': 'Host1.com'})
  • python3

    1OrderedDict([('Accept-Language', 'en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4'), ('Accept-Encoding', 'gzip, deflate, sdch'), ('cache', 0), ('host', 'Host1.com'), ('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'), ('User-Agent', 'curl/7.29.0'), ('Host', 'Host2.com')])
    2{'Accept-Language': 'en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4', 'Accept-Encoding': 'gzip, deflate, sdch', 'cache': 0, 'Host': 'Host2.com', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'User-Agent': 'curl/7.29.0'}

所以如果要兼容两个版本,需要显示的传入

1headers = OrderedDict(sorted(headers.items(), key=lambda x: x[0]))

django

1- for k, v in request.GET.iterlists():
2+ for k, v in request.GET.lists():

并且k和v的类型在python3里默认为 str , 不需要使用 k.encode("utf-8") 进行转换

作者: honmaple
链接: https://honmaple.me/articles/2021/03/python2升级至python3.html
版权: CC BY-NC-SA 4.0 知识共享署名-非商业性使用-相同方式共享4.0国际许可协议
wechat
alipay

加载评论