写py2、py3兼容的代码

写py2、py3兼容的代码

用到一段时间python,之前也重点复习了一次python3。但工作中运行环境是python2.7,于是要求写出py2、py3都兼容的代码。下面将涉及到的几点技巧列举出来以备忘。

print函数

py3中print语句没有了,取而代之的是print()函数。 Python 2.6与Python 2.7部分地支持这种形式的print语法。因此保险起见,新写的代码都使用print函数。

from __future__ import print_function
print("fish", "panda", sep=', ')

Unicode

Python 2 有 ASCII str() 类型,unicode() 是单独的,不是 byte 类型。

现在, 在 Python 3,我们最终有了 Unicode (utf-8) 字符串,以及一个字节类:byte 和 bytearrays。

由于 Python3.X 源码文件默认使用utf-8编码,这就使得以下代码是合法的:

>>> 中国 = 'china' 
>>>print(中国) 
china

Python 2.x

>>> str = "我爱北京天安门"
>>> str
'\xe6\x88\x91\xe7\x88\xb1\xe5\x8c\x97\xe4\xba\xac\xe5\xa4\xa9\xe5\xae\x89\xe9\x97\xa8'
>>> str = u"我爱北京天安门"
>>> str
u'\u6211\u7231\u5317\u4eac\u5929\u5b89\u95e8'

Python 3.x

>>> str = "我爱北京天安门"
>>> str
'我爱北京天安门'

个人还是喜欢py3的这种明确两种不同类型的方案,因此新写的代码都使用以下方案。

from __future__ import unicode_literals
txt='中国'
>>> txt
u'\u4e2d\u56fd'
>>> type(txt)
<type 'unicode'>
>>> print(txt)
中国
arr=b'abcd'
>>> arr
'abcd'
>>> type(arr)
<type 'str'>
>>> print(arr)
abcd

除法运算

在python 2.x中/除法就跟我们熟悉的大多数语言,比如Java啊C啊差不多,整数相除的结果是一个整数,把小数部分完全忽略掉,浮点数除法会保留小数点的部分得到一个浮点数的结果。

在python 3.x中/除法不再这么做了,对于整数之间的相除,结果也会是浮点数。

而对于//除法,这种除法叫做floor除法,会对除法的结果自动进行一个floor操作,在python 2.x和python 3.x中是一致的。注意的是floor除法并不是舍弃小数部分,而是执行floor操作,如果要截取小数部分,那么需要使用math模块的trunc函数。

个人还是喜欢py3这种方案,毕竟是从java转过来的,因此新定的代码都使用以下方案。

from __future__ import division
>>> 1/2
0.5
>>> 1//2
0
>>> trunc(1/2)
0
>>> -1//2
-1
>>> trunc(-1/2)
0

异常

在 Python 3 中处理异常也轻微的改变了,在 Python 3 中我们现在使用 as 作为关键词。

捕获异常的语法由 except exc, var 改为 except exc as var

使用语法except (exc1, exc2) as var可以同时捕获多种类别的异常。 Python 2.6已经支持这两种语法。

  • 在2.x时代,所有类型的对象都是可以被直接抛出的,在3.x时代,只有继承自BaseException的对象才可以被抛出。
  • 2.x raise语句使用逗号将抛出对象类型和参数分开,3.x取消了这种奇葩的写法,直接调用构造函数抛出对象即可。

这里倒没有异议了,本来就常见原来py2那种奇葩写法很奇怪,只使用py3的写法就可以了。

try:
    raise BaseException('fdf')
except BaseException as err:
    print(err)

八进制字面量表示

八进制数必须写成0o777,原来的形式0777不能用了;二进制必须写成0b111。

新增了一个bin()函数用于将一个整数转换成二进制字串。 Python 2.6已经支持这两种语法。

在Python 3.x中,表示八进制字面量的方式只有一种,就是0o1000。

很简单,只使用py3支持的写法。

不等运算符

Python 2.x中不等于有两种写法 != 和 <>。

Python 3.x中去掉了<>, 只有!=一种写法,还好,我从来没有使用<>的习惯。

数据类型

  • Py3.X去除了long类型,现在只有一种整型——int,但它的行为就像2.X版本的long
  • 新增了bytes类型,对应于2.X版本的八位串

这里如果要进行类型判断,优先使用six模块提供的兼容功能。

  • six.class_types Possible class types. In Python 2, this encompasses old-style and new-style classes. In Python 3, this is just new-styles.
  • six.integer_types Possible integer types. In Python 2, this is long and int, and in Python 3, just int.
  • six.string_types Possible types for text data. This is basestring() in Python 2 and str in Python 3.
  • six.text_type Type for representing (Unicode) textual data. This is unicode() in Python 2 and str in Python 3.
  • six.binary_type Type for representing binary data. This is str in Python 2 and bytes in Python 3.
import six

def dispatch_types(value):
    if isinstance(value, six.integer_types):
        handle_integer(value)
    elif isinstance(value, six.class_types):
        handle_class(value)
    elif isinstance(value, six.string_types):
        handle_string(value)

dict的相关方法调整

dict的.keys()、.items 和.values()方法返回迭代器,而之前的iterkeys()等函数都被废弃。同时去掉的还有 dict.has_key(),用 in替代它吧。

这里还是使用six模块提供的兼容功能。

  • six.iterkeys(dictionary, ***kwargs*) Returns an iterator over dictionary‘s keys. This replaces dictionary.iterkeys() on Python 2 and dictionary.keys() on Python 3. kwargs are passed through to the underlying method.
  • six.itervalues(dictionary, ***kwargs*) Returns an iterator over dictionary‘s values. This replaces dictionary.itervalues() on Python 2 and dictionary.values() on Python 3. kwargs are passed through to the underlying method.
  • six.iteritems(dictionary, ***kwargs*) Returns an iterator over dictionary‘s items. This replaces dictionary.iteritems() on Python 2 and dictionary.items() on Python 3. kwargs are passed through to the underlying method.
  • six.iterlists(dictionary, ***kwargs*) Calls dictionary.iterlists() on Python 2 and dictionary.lists() on Python 3. No builtin Python mapping type has such a method; this method is intended for use with multi-valued dictionaries like Werkzeug’s.kwargs are passed through to the underlying method.
  • six.viewkeys(dictionary) Return a view over dictionary‘s keys. This replaces dict.viewkeys() on Python 2.7 and dict.keys() on Python 3.
  • six.viewvalues(dictionary) Return a view over dictionary‘s values. This replaces dict.viewvalues() on Python 2.7 and dict.values() on Python 3.
  • six.viewitems(dictionary) Return a view over dictionary‘s items. This replaces dict.viewitems() on Python 2.7 and dict.items() on Python 3.

标准库及函数名称变更

py3重新组织了一些标准库及一些函数,为了保证在py2、py3下代码都工作正常,这里使用six模块提供的兼容功能。

1

from six.moves.cPickle import loads

Supported renames:

Name

Python 2 name

Python 3 name

builtins

__builtin__

builtins

configparser

ConfigParser

configparser

copyreg

copy_reg

copyreg

cPickle

cPickle

pickle

cStringIO

cStringIO.StringIO()

io.StringIO

dbm_gnu

gdbm

dbm.gnu

_dummy_thread

dummy_thread

_dummy_thread

email_mime_multipart

email.MIMEMultipart

email.mime.multipart

email_mime_nonmultipart

email.MIMENonMultipart

email.mime.nonmultipart

email_mime_text

email.MIMEText

email.mime.text

email_mime_base

email.MIMEBase

email.mime.base

filter

itertools.ifilter()

filter()

filterfalse

itertools.ifilterfalse()

itertools.filterfalse()

getcwd

os.getcwdu()

os.getcwd()

getcwdb

os.getcwd()

os.getcwdb()

http_cookiejar

cookielib

http.cookiejar

http_cookies

Cookie

http.cookies

html_entities

htmlentitydefs

html.entities

html_parser

HTMLParser

html.parser

http_client

httplib

http.client

BaseHTTPServer

BaseHTTPServer

http.server

CGIHTTPServer

CGIHTTPServer

http.server

SimpleHTTPServer

SimpleHTTPServer

http.server

input

raw_input()

input()

intern

intern()

sys.intern()

map

itertools.imap()

map()

queue

Queue

queue

range

xrange()

range

reduce

reduce()

functools.reduce()

reload_module

reload()

imp.reload(), importlib.reload() on Python 3.4+

reprlib

repr

reprlib

shlex_quote

pipes.quote

shlex.quote

socketserver

SocketServer

socketserver

_thread

thread

_thread

tkinter

Tkinter

tkinter

tkinter_dialog

Dialog

tkinter.dialog

tkinter_filedialog

FileDialog

tkinter.FileDialog

tkinter_scrolledtext

ScrolledText

tkinter.scrolledtext

tkinter_simpledialog

SimpleDialog

tkinter.simpledialog

tkinter_ttk

ttk

tkinter.ttk

tkinter_tix

Tix

tkinter.tix

tkinter_constants

Tkconstants

tkinter.constants

tkinter_dnd

Tkdnd

tkinter.dnd

tkinter_colorchooser

tkColorChooser

tkinter.colorchooser

tkinter_commondialog

tkCommonDialog

tkinter.commondialog

tkinter_tkfiledialog

tkFileDialog

tkinter.filedialog

tkinter_font

tkFont

tkinter.font

tkinter_messagebox

tkMessageBox

tkinter.messagebox

tkinter_tksimpledialog

tkSimpleDialog

tkinter.simpledialog

urllib.parse

See six.moves.urllib.parse

urllib.parse

urllib.error

See six.moves.urllib.error

urllib.error

urllib.request

See six.moves.urllib.request

urllib.request

urllib.response

See six.moves.urllib.response

urllib.response

urllib.robotparser

robotparser

urllib.robotparser

urllib_robotparser

robotparser

urllib.robotparser

UserDict

UserDict.UserDict

collections.UserDict

UserList

UserList.UserList

collections.UserList

UserString

UserString.UserString

collections.UserString

winreg

_winreg

winreg

xmlrpc_client

xmlrpclib

xmlrpc.client

xmlrpc_server

SimpleXMLRPCServer

xmlrpc.server

xrange

xrange()

range

zip

itertools.izip()

zip()

zip_longest

itertools.izip_longest()

itertools.zip_longest()

这里用得比较多的是:

import six.moves.configparser
import six.moves.cPickle
import six.moves.cStringIO
import six.moves.filter
import six.moves.filterfalse
import six.moves.getcwd
import six.moves.http_cookies
import six.moves.html_entities
import six.moves.html_parser
import six.moves.http_client
import six.moves.BaseHTTPServer
import six.moves.CGIHTTPServer
import six.moves.SimpleHTTPServer
import six.moves.input
import six.moves.map
import six.moves.queue
import six.moves.range
import six.moves.reduce
import six.moves.socketserver
import six.moves.zip
import six.moves.zip_longest
import six.moves.urllib.parse
import six.moves.urllib.error
import six.moves.urllib.request
import six.moves.urllib.response

只有按这个方案导入其它模块,即可保证在py2、py3下都可正确导入模块,详细可参看six模块的文档

版本指示变量

最后如果在py2、py3下逻辑不一致,可使用版本指示变量。

  • six.PY2 A boolean indicating if the code is running on Python 2.
  • six.PY3 A boolean indicating if the code is running on Python 3.
import six

if six.PY2:
    # do some thing
    pass
elif six.PY3:
    # do other thing
    pass

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏HansBug's Lab

1901: Zju2112 Dynamic Rankings

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MB Submit: ...

2776
来自专栏Python小屋

Python花式编程案例锦集(1)

首先解答上一篇文章详解Python中的序列解包(2)中最后的习题,该题答案为5,表达式功能为迭代求解序列中元素的最大值。 -----------------分割...

3795
来自专栏debugeeker的专栏

《coredump问题原理探究》Linux x86版3.3节栈布局之局部变量

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhina/article/detai...

831
来自专栏Python爬虫实战

Google Python风格规范(上)

好的代码风格,给人舒服的感觉,今天介绍一下谷歌的Python风格规范,由于规范比较多,将分为两次介绍。

1022
来自专栏恰同学骚年

C# 中的委托和事件

文中代码在VS2005下通过,由于VS2003(.Net Framework 1.1)不支持隐式的委托变量,所以如果在一个接受委托类型的位置直接赋予方法名,...

982
来自专栏张善友的专栏

在Entity Framework 中执行T-sql语句

从Entity Framework  4开始在ObjectContext对象上提供了2个方法可以直接执行SQL语句:ExecuteStoreQuery<T> 和...

22310
来自专栏偏前端工程师的驿站

PLT:说说Evaluation strategy

Brief                                 在学习方法/函数时,我们总会接触到 按值传值 和 引用传值 两个概念。像C#是按值传...

2086
来自专栏令仔很忙

限制字符串输入——正则表达式(VB.NET)

在做机房收费系统的时候,几乎所有的窗体上都存在着文本框或者组合框,当用户进行操作的时候,首先要判断是否为空,然后再对各种属性进行判断,比如;卡号、学号、金额等...

2481
来自专栏java一日一条

UML类图五种关系与代码的对应关系

注意1: Water类的生命期,它是当Animal类的GrounUp方法被调用的时候,才被实例化。

2411
来自专栏Pythonista

Python3编程技巧

Microsoft Excel是Microsoft为使用Windows和Apple Macintosh操作系统的计算机编写的一款电子表格软件。直观的界面、出色的...

1022

扫码关注云+社区

领取腾讯云代金券