python和python3如何兼容_如何写一个基本兼容python2和python3的程序?

看 p牛fpm未授权访问到rce的poc 兼容python2和python3,看了一下代码,开头一部分是这样的:

...

PY2 = True if sys.version_info.major == 2 else False

def bchr(i):

if PY2:

return force_bytes(chr(i))

else:

return bytes([i])

def bord(c):

if isinstance(c, int):

return c

else:

return ord(c)

def force_bytes(s):

if isinstance(s, bytes):

return s

else:

return s.encode('utf-8', 'strict')

def force_text(s):

if issubclass(type(s), str):

return s

if isinstance(s, bytes):

s = str(s, 'utf-8', 'strict')

else:

s = str(s)

return s

...

在开头定义了一个变量 PY2 判断当前的环境是Python2还是Python3,在 bchr() 函数里,如果是python2的环境,强制转换为字节流然后返回,是python3的话使用 bytes() 转换为字节对象返回。下面三个函数都是使用 isinstance() 判断变量是否为对应的类型,为假则转换为对应的类型

这四个函数主要解决的是Python2和Python3中字符串类型str和bytes的问题,Python3中将字符串区分为文本(str)和字节流(bytes)类型,我们在代码中使用引号包裹起来的字符串都是文本(str)类型的:

0d6b33f34861510861a2e9ef607592d0.png

而在网络上传输的数据,或是从磁盘中读写的数据都是字节流的:

c9d47fdb87308f47fcc7b9e8b644c424.png

而这时如果我要使用正则表达式来从响应报文中匹配数据,就不能直接re.findall(正则,content)了:

ea7f1b53dc11354397bf28cd5beaa7e3.png

提示我们不能在bytes的字符串中使用str的字符串去匹配,Python3并不会隐式转换str和bytes。

但我们在Python2中使用同样的代码:

65562ba4c064b76a05053aa5ada52047.png

(PS 单独Python3可以这么写:

d82b104d4012addc49977dfeb2fb19dc.png

)

Python2和Python3的字符串好像有点乱?记个表格吧,之后也用得上:

版本

文本

字节

python2

Unicode

str

python3

str

bytes

所以开头的四个函数主要用于解决Python2和Python3字符串的问题,有了这四个函数就可以这么写来解决问题了:

bab82c01ecc3e05cfe6890111f2ddafb.png

Python3自带的 __future__

但是Python2和Python3的差别不止上面一个字符串,Python官方自带了一个 __future__ 模块用于兼容python2和python3。

__funture__ 的官方文档在这里: https://docs.python.org/zh-cn/3/library/__future__.html ,版本可在左上角切换,里面给出了 __funture__ 支持的一些特性:

0d701c557dffd27bf8d78d9f6fa4d474.png

division

/ 表示除法,在python2和python3中表现略微不一样,具体见下表:

版本

整除

除法

python2

/ (当除数与被除数均为整数)

/ (当除数与被除数中有一个为浮点数)

python3

//

/

当使用了 from __future__ import division 可以确保 / 在python2和python3中表现得一致:

ea0c16b4819104846b70c6b0c167d20d.png

6e57d3bfba7e8b2b88b8583bb278ebd2.png

absolute_import

绝对导入/相对导入是指,通过 import foo 导入一个模块时,在python自带的模块中存在一个foo.py,在本目录下也存在一个foo.py,优先导入系统/本目录的模块。python2.4之前默认是优先导入本目录下的模块,如果是需要导入python的自带模块,则需要使用 from __future__ import absolute_import 。

with_statement

with复合语句是从python2.5中引入的,低于2.5版本的python使用with语句需要另外引入。

不过现在常见的python2版本已经是2.7了,基本用不上这个了 :)

print_function

强制使用 print() 这种形式的输出。

举个栗子:

from __future__ import print_function

print('ok')

print 'ok'

正常情况下,python2有 print 'ok' 这种写法的,但当引入了 print_function ,则python2会对 print 'ok' 的写法报错:

ff1beec634c73e198358402fa777fdda.png

unicode_literal

对字符串使用Unicode编码,在python2早期中不支持Unicode编码,所以中文等一些字符会出现乱码。

第三方模块six

six(6)的名字取自2*3=6

统一类型

补充一下我们的表格:

版本

文本

字节

python2

Unicode

str

python3

str

bytes

six

six.text_type

six.binary_type

six把python的文本统一为 six.text_type ,把字节统一为 six.binary_type

976ef3dcf11b922dc5b8036acf798956.png

5bf6df3baf05729a99fccdf78d3ee9bb.png

内部对象属性的重命名和模块的统一

Python3重新组织了标准库,并将一些函数移到了不同的模块中。six通过 six.moves 模块为它们提供了一致的接口。

—— six官方在线文档

例如python2的HTMLParser模块,在python3中变为了html.parser,python2的 import HTMLParser 和python3的 import html.parser 在引入six之后,都可以使用 from six.moves import html_parser 来引入了。

其他高级自定义的方法等

比如使用 from six.moves import input 来统一 input() 的返回值类型全为str:

转换Python2的input()类型为str:

4bac14816ce58495a71a1bd72b2fde62.png

Python3的input()即为str类型:

b8d0956b47b7dd211cac8bc210201567.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值