将非多语言代码从 Py2 移植到 Py3 的巧妙方法
Neat way to port nonpolyglot code from Py2 to Py3
在我的许多 python 模块中,我都在使用
from itertools import izip_longest
但现在我正在将我的代码库迁移到 Py3(同时兼容 Py2)。在 Py3 中 izip_longest 被重命名为 zip_longest。 中推荐了一种解决此问题的方法,即将导入语句更改为以下内容。
try:
# Python 3
from itertools import zip_longest as izip_longest
except ImportError:
# Python 2
from itertools import izip_longest
但是,在 20 多个模块中进行更改对我来说有点奇怪。这样做的巧妙方法是什么?
您可以将确切的代码包装在您自己的模块中,比如 itertools_compat.py
,然后只写
from itertools_compat import izip_longest
任何你需要这个功能的地方。
使 python2 代码与 python3 一起工作不是免费的。
并且涉及大量 g运行t 工作。
我认为很难避免这种情况,无论如何您都必须进行适当的测试以确保您的代码适用于两个版本。
我不知道你的代码和你的项目,它的确切内容,这个项目是否应该存活更长时间,或者你是否只是想让它存活更长时间。因此,我不确定在您的情况下什么是最好的。
一般来说,我会建议更改您的代码,使其看起来像 python3 代码,并且仍然 运行s 与 python2 而不是编写看起来像 python2 代码,还有 运行 和 python3。 (但这一切都取决于你的背景)
您可能想试用包 future
https://python-future.org/
它提供编写代码的帮助程序,即 运行 两个版本。
future
还包含一些工具,这些工具会尝试以某种方式自动更改代码,这两个版本更有可能 运行。
根据代码的复杂性,您仍然需要手动执行很多操作(尤其是对于 unicode 问题)
命令被称为 futurize
(使代码看起来像 python3 但 运行 与 python2)
或 pasteurize
(使代码看起来像 python2 但 运行 也与 python3)
在尝试之前备份所有文件(或使用一些版本控制,如 git)。
简单的用例是futurize --stage1 yourfile.py
有一个有趣的章节/备忘单有很多例子,值得一读https://python-future.org/compatible_idioms.html?highlight=zip
如果您不想使用 future 包,或者遇到这种情况,future 不能很好地处理我会编写一个适配器模块并在您的代码中使用它。
例如
py2py3compat.py:
try:
# Python 3
from itertools import zip_longest
except ImportError:
# Python 2
from itertools import izip_longest as zip_longest
yourpyfile.py:
from py2py3compat import zip_longest
并执行全局搜索和替换以将 izip_longest
替换为 zip_longest
我看到你的其他问题已关闭,所以我会 post 在这里。
所以,有几个文件,命名很重要!
fixer.py
#!/usr/bin/env python3
# you'll need 2to3 and python-modernize installed
from __future__ import absolute_import
import sys
from lib2to3.main import main
import libmodernize
sys.path.append(".")
sys.exit(main('fixers'))
fixers/fix_iziplongest.py
from lib2to3 import fixer_base
import libmodernize
class FixIziplongest(fixer_base.BaseFix):
PATTERN = """
power< 'izip_longest' trailer< '(' any* ')' > >
| import_from< 'from' 'itertools' 'import' 'izip_longest' >
"""
# This function is only called on matches to our pattern, which should
# be usage of izip_longest, and the itertools import
def transform(self, node, results):
# add the new import (doesn't matter if we do this multiple times
libmodernize.touch_import('itertools_compat', 'zip_longest', node)
# remove the old import
if node.type == syms.import_from:
node.parent.remove()
return node
# rename to izip_longest
node.children[0].value = 'zip_longest'
return node
用法与 2to3
- python ./fixer.py -f iziplongest file_to_fix.py
相同(如果您希望它应用更改,则可以添加更多标志,这只会显示差异)
所以,它的作用是隐藏这个:
from itertools import izip_longest
for x in izip_longest(a, b):
print(x)
为此:
from itertools_compat import zip_longest
for x in zip_longest(a, b):
print(x)
在我的许多 python 模块中,我都在使用
from itertools import izip_longest
但现在我正在将我的代码库迁移到 Py3(同时兼容 Py2)。在 Py3 中 izip_longest 被重命名为 zip_longest。
try:
# Python 3
from itertools import zip_longest as izip_longest
except ImportError:
# Python 2
from itertools import izip_longest
但是,在 20 多个模块中进行更改对我来说有点奇怪。这样做的巧妙方法是什么?
您可以将确切的代码包装在您自己的模块中,比如 itertools_compat.py
,然后只写
from itertools_compat import izip_longest
任何你需要这个功能的地方。
使 python2 代码与 python3 一起工作不是免费的。 并且涉及大量 g运行t 工作。 我认为很难避免这种情况,无论如何您都必须进行适当的测试以确保您的代码适用于两个版本。
我不知道你的代码和你的项目,它的确切内容,这个项目是否应该存活更长时间,或者你是否只是想让它存活更长时间。因此,我不确定在您的情况下什么是最好的。
一般来说,我会建议更改您的代码,使其看起来像 python3 代码,并且仍然 运行s 与 python2 而不是编写看起来像 python2 代码,还有 运行 和 python3。 (但这一切都取决于你的背景)
您可能想试用包 future
https://python-future.org/
它提供编写代码的帮助程序,即 运行 两个版本。
future
还包含一些工具,这些工具会尝试以某种方式自动更改代码,这两个版本更有可能 运行。
根据代码的复杂性,您仍然需要手动执行很多操作(尤其是对于 unicode 问题)
命令被称为 futurize
(使代码看起来像 python3 但 运行 与 python2)
或 pasteurize
(使代码看起来像 python2 但 运行 也与 python3)
在尝试之前备份所有文件(或使用一些版本控制,如 git)。
简单的用例是futurize --stage1 yourfile.py
有一个有趣的章节/备忘单有很多例子,值得一读https://python-future.org/compatible_idioms.html?highlight=zip
如果您不想使用 future 包,或者遇到这种情况,future 不能很好地处理我会编写一个适配器模块并在您的代码中使用它。
例如 py2py3compat.py:
try:
# Python 3
from itertools import zip_longest
except ImportError:
# Python 2
from itertools import izip_longest as zip_longest
yourpyfile.py:
from py2py3compat import zip_longest
并执行全局搜索和替换以将 izip_longest
替换为 zip_longest
我看到你的其他问题已关闭,所以我会 post 在这里。 所以,有几个文件,命名很重要!
fixer.py
#!/usr/bin/env python3
# you'll need 2to3 and python-modernize installed
from __future__ import absolute_import
import sys
from lib2to3.main import main
import libmodernize
sys.path.append(".")
sys.exit(main('fixers'))
fixers/fix_iziplongest.py
from lib2to3 import fixer_base
import libmodernize
class FixIziplongest(fixer_base.BaseFix):
PATTERN = """
power< 'izip_longest' trailer< '(' any* ')' > >
| import_from< 'from' 'itertools' 'import' 'izip_longest' >
"""
# This function is only called on matches to our pattern, which should
# be usage of izip_longest, and the itertools import
def transform(self, node, results):
# add the new import (doesn't matter if we do this multiple times
libmodernize.touch_import('itertools_compat', 'zip_longest', node)
# remove the old import
if node.type == syms.import_from:
node.parent.remove()
return node
# rename to izip_longest
node.children[0].value = 'zip_longest'
return node
用法与 2to3
- python ./fixer.py -f iziplongest file_to_fix.py
相同(如果您希望它应用更改,则可以添加更多标志,这只会显示差异)
所以,它的作用是隐藏这个:
from itertools import izip_longest
for x in izip_longest(a, b):
print(x)
为此:
from itertools_compat import zip_longest
for x in zip_longest(a, b):
print(x)