使用_compat.py实现py2,py3的兼容¶
six是一个比较流行的py2和py3兼容的包,不过它有些大和复杂。在werkzeug中,提供了一个类似的包叫 _compat.py, 它比较轻量。因此uliweb在它的基础上进行了一些定制。那么使用 _compat.py 实现py2和py3的兼容应该如何做?
引入future特性¶
主要是引用 print, unicode, 绝对路径导入相关的future支持,如:
from __future__ import print_function, absolute_import, unicode_literals
以上导入,将使你的.py文件可以使用 print()
,字符串缺省认为是unicode。
不兼容的语法支持¶
从 _compat.py
中设置了一些py2, py3不兼容的语法支持,主要有:
name | 2.x | 3.x |
---|---|---|
unichr | unichr | chr |
unicode | unicode | str |
range | xrange | range |
string_types | (str, unicode) | (str, ) |
pickle | cPickle | pickle |
input | raw_input | input |
open | open | from io import open |
pickle | import cPickle as pickle | import pickle |
u(转unicode) | 与unicode进行比较 | 与str进行比较 |
b(转bytes) | 与unicode进行比较 | 与bytes进行比较 |
exec_ | exec 语句 | exec 函数 |
语句 | 函数 | |
callable | callable | hasattr(x, '__call__') |
ismethod | 使用inspect.ismethod | 判断 '.' in f.qualname |
isfunction | 使用inspect.isfunction | 判断 '.' not in f.qualname |
示例:
from ._compat import input, with_metaclass, string_types
StringIO, BytesIO 可以通一从io导入。
metaclass 支持¶
示例:
from ._compat import with_metaclass
class CommandMetaclass(type):
def __init__(cls, name, bases, dct):
option_list = list(dct.get('option_list', []))
for c in bases:
if hasattr(c, 'option_list') and isinstance(c.option_list, list):
option_list.extend(c.option_list)
cls.option_list = option_list
class Command(with_metaclass(CommandMetaclass)):
option_list = ()
help = ''
args = ''
def create_parser(self, prog_name, subcommand):
"""
Create and return the ``OptionParser`` which will be used to
parse the arguments to this command.
"""
导入位置结构变动模块¶
在py3中,有些模块的位置结构发生了变化,或者模块名改为了纯小写,所以为了兼容统一提供了 import_
函数,原型为:
def import_(module, objects=None, py2=None):
"""
:param module: py3 compatiable module path
:param objects: objects want to imported, it should be a list
:param via: for some py2 module, you should give the import path according the
objects which you want to imported
:return: object or module
Usage:
import_('urllib.parse', 'urlparse')
import_('urllib.parse', ['urlparse', 'urljoin'])
import_('urllib.parse', py2='urllib2')
"""
其中 module
为按py3的结构定义的模块路径,如 urllib.parse
,objects
为计划导出的对象。py2
表示当特殊 情况下, _compat.py
未提供缺省映射时,可以指定在py2环境时,使用哪个py2的模块来导入 objects
。
关于哪些模块可以通用 import_
来导入,可以看 uliweb/utils/_compat.py
的源码。