在Python 3.x中使print像Python 2中的语句一样工作

26
我不知道是否可以使打印函数(不改变所有地方的语法)像Python 2及其早期版本那样运行。

因此,我的语句如下:

print "Hello, World!"

我希望这种语法可以在Python 3中工作。我尝试导入six库,但那并没有起作用(仍然是语法错误)。


4
哈哈,我也想要完全一样的东西。我喜欢 Python 3 的所有东西,除了 print 语句。 - gunit
5个回答

20
不可以。在Python 3中,print语句已经被取消了;编译器不再支持它。
你可以让print()在Python 2中像一个函数一样工作;只需在每个使用print的模块顶部添加以下代码:
from __future__ import print_function

这将删除Python 2中对print语句的支持,就像在Python 3中一样,并且您可以使用随Python 2一起提供的print()函数。但是six只能帮助桥接同时考虑Python 2和3的代码; 这包括首先用print()函数替换print语句。您可能想阅读Porting Python 2 Code to Python 3 howto; 它将告诉您更多类似的from __future__导入,以及介绍诸如ModernizeFuturize等工具,可帮助自动修复Python 2代码以在Python 2和3上运行。

5
很遗憾 - 我需要执行第三方提供的代码,但我真的不喜欢去修改所有那些print语句的代码 :/。(您在描述相反的问题:我确实使用Python 3编程,但我需要运行由使用Python 2的人编写的代码) - paul23
1
@paul23:抱歉,使用了错误的工具。你应该尝试使用2to3实用程序自动修复Python 2代码。 - Martijn Pieters
1
@paul23 如果你真的对Python的语句和关键字机制感兴趣,你可能会喜欢阅读这篇文章:http://mathamy.com/import-accio-bootstrapping-python-grammar.html。 - OzTamir
我的情况更糟... 我有一些预处理数据,其中包含带有打印语句的对象... 代码转换器不能翻译对象的成员函数,我想。 - ymeng
@ymeng:代码翻译可以很好地处理成员函数。 - Martijn Pieters

9
您可以使用正则表达式将 Python 2 中的 print 代码替换为 Python 3:
Find:
(print) (.*)(\n)

Replace with:
$1($2)$3

正则表达式在什么上下文中?在Perl脚本中吗?这将不能适用于所有正则表达式的风格。你能提供一个例子吗(通过编辑你的答案,而不是在评论中,不要加"编辑:","更新:"或类似的字样)? - Peter Mortensen

8
您可以使用工具 2to3 ,这是一个自动将Python 2代码转换为Python 3的工具。正如@Martijn Pieters♦所说的那样,您可以通过它轻松地从旧版Python迁移到Python 3,并使更改生效。我举了一个简单的例子:

我创建了这个文件,python2.py:

#!python3

print 5

当我使用Python运行它时,显然会显示:
line 3
    print 5          ^
SyntaxError: Missing parentheses in call to 'print'

因此,你可以通过终端来进行转换,像这样:

这是重要的命令

$ 2to3 -w home/path_to_file/python2.py

-w参数将会写入文件,如果你只想查看未来的更改而不应用它们,只需运行它而不加-w参数。 运行后,它会显示类似于以下内容:

root: Generating grammar tables from /usr/lib/python2.7/lib2to3/PatternGrammar.txt
RefactoringTool: Refactored Desktop/stackoverflow/goto.py
--- Desktop/stackoverflow/goto.py   (original)
+++ Desktop/stackoverflow/goto.py   (refactored)
@@ -1,3 +1,3 @@
 #!python3

-print 5
+print(5)
RefactoringTool: Files that were modified:

文件将会是这个样子:

#!python3

print(5)

2to3 不工作得很好 - 它不能很好地转换: print('x'+'a') - Nathan B

2
如果你可以覆盖builtins.__import__并使用简单的正则表达式来转换没有括号的打印语句,那么你可以按照以下步骤操作。请注意,这实际上不会更改任何文件,只是在导入它们时将代码读入字符串中,调整该字符串,然后将修复后的代码发送给编译器/导入器。
import re
import sys
if sys.version_info >= (3, 0):
  import lib2to3
  from lib2to3 import main, refactor
  import os
  import types
  import builtins
  import sys
  import importlib

  cache = {}

  prevImport = builtins.__import__

  def customImport(path, *args, **kwargs):
    #print (path, args, kwargs)
    try:
      return fimport(path + ".py")
    except:
      return prevImport(path, *args, **kwargs)

  def reload(filename):
    fimport(filename.__file__, forceReload=True)

  def fimport(filename, forceReload=False):
    filename = os.path.abspath(filename)
    modulePath = os.path.splitext(os.path.basename(filename))[0]
    if filename in cache and not forceReload:
      execval, modifyTime, module = cache[filename]
      if modifyTime == os.path.getmtime(filename):
        return module
    f = open(filename)
    text = f.read() + "\n"
    p = re.compile("print")
    res = []
    curI = 0
    for m in p.finditer(text):
      i = m.start()
      res.append(text[curI:i])
      curI = i
      pieceTmp = text[i:].split("\n")[0]
      piece = text[i:].split("\n")[0].split("#")[0]
      pieceAfter = piece[len('print'):].strip()
      if pieceAfter[0] != '(':
        resLine = "print" + "(" + pieceAfter + ")" + "\n"
        res.append(resLine)
      else:
        res.append(pieceTmp)
      curI += len(pieceTmp)+1
    text = "".join(res)
    f.close()
    '''
    # this code can run lib2to3 if you want but just for replacing prints that is not needed
    #fixes = sorted(lib2to3.refactor.get_fixers_from_package('lib2to3.fixes'))
    fixes = ['lib2to3.fixes.fix_print']
    rt = lib2to3.main.StdoutRefactoringTool(fixes, {}, [], False, False)
    res = str(rt.refactor_string(text, name=modulePath))
    '''
    res = text
    res = compile(res, '<string>', 'exec')
    module = types.ModuleType(modulePath)
    module.__file__ = filename
    cache[filename] = (res, os.path.getmtime(filename), module)
    exec(res, module.__dict__)
    return module


  builtins.__import__ = customImport
  importlib.reload = reload

如果您将这段代码保存为pastimport.py,假设我有一个名为juniper.py的文件:
def wow(a):
  print a

现在如果我想从python3调用juniper.py,我只需要执行以下操作:
import pastimport
import juniper

juniper.wow("bean")

这将可以运行 :)

这可能会更快,并且更像典型的导入方式,具有缓存和日志记录等功能,但我还不太明白pyc文件是如何生成的,以及何时生成。对于c插件等边缘情况,我也不确定。因此,欢迎提出改进建议,但至少这是一个概念验证。我认为您应该能够实际调整解释器输入和当前文件的值,但我正在尝试。

技术上,这也允许您导入任何python2文件(2to3修复xrange,print等),如果这些文件导入其他python2文件,则它们也会被转换,因为这覆盖了每个人都使用的导入方式。您还可以实现任意操作符重载,要求静态类型,实际上需要花括号,甚至可以使用此单个导入从其他语言导入代码或更改Python。但我跑题了。


1
这将尝试在所有内容上运行2to3,无论它是否实际上是Python 2代码。 - user2357112
2to3对Python 3代码的处理很好(它不会进行任何更改),但是我同意有很多特殊情况需要考虑(例如.pyd)。这很容易解决,因为您可以调用原始的导入函数,但我在这里还没有添加检查。理想情况下,它应该能够生成.pyc文件。请随时提出修改建议。 - Phylliida
尝试在print(1,2)上运行2to3,你会发现在Python 3代码上运行2to3是不安全的。 - user2357112
我得到了(1, 2)(在同一个文件中有print a),这正是Python3所做的。而且像print(1,2)\nprint('games', end='')这样的东西也可以正常工作。 - Phylliida
哦,算了,它并没有起作用(我肯定是在想错了什么)。所以你是对的,我相信一些特例分析可以解决这个问题,但这肯定会更加粗略。 - Phylliida
好的,我使用了一个简单的正则表达式来替换它,理论上现在应该能够良好地工作(可能还有一些边缘情况我没有考虑到,所以使用时需要自行承担风险,但这可以为您提供一个很好的起点)。 - Phylliida

0
以下代码片段适用于交互式使用。当出现打印语法错误时,脚本会再次执行失败的命令,并在python3中用“()”括起来。
#!/usr/bin/python3.8 -i
import subprocess, shlex, sys, readline, traceback
def excepthook(exctype, value, tb):
    if exctype is SyntaxError:
        index = readline.get_current_history_length()
        command = readline.get_history_item(index)
        if command.find("print") != -1:
            sp =  command.split("print")[1]
            new = "print" + "(" + sp + ")"
            eval(new)  
    else:
        traceback.print_exception(exctype, value, tb)
sys.excepthook = excepthook

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接