使用_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不兼容的语法支持,主要有:

name2.x3.x
unichrunichrchr
unicodeunicodestr
rangexrangerange
string_types(str, unicode)(str, )
picklecPicklepickle
inputraw_inputinput
openopenfrom io import open
pickleimport cPickle as pickleimport pickle
u(转unicode)与unicode进行比较与str进行比较
b(转bytes)与unicode进行比较与bytes进行比较
exec_exec 语句exec 函数
print语句函数
callablecallablehasattr(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.parseobjects 为计划导出的对象。py2 表示当特殊 情况下, _compat.py 未提供缺省映射时,可以指定在py2环境时,使用哪个py2的模块来导入 objects

关于哪些模块可以通用 import_ 来导入,可以看 uliweb/utils/_compat.py 的源码。

参考文档

https://www.cnblogs.com/davidwang456/p/7493795.html