20

I wonder if the print function can be made work (without changing the syntax all over the place) like in Python 2 and earlier.

So I have the statement like:

print "Hello, World!"

And I like that syntax to work in Python 3. I've tried importing the library six, but that didn't do the trick (still a syntax error).

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
paul23
  • 7,226
  • 9
  • 44
  • 108
  • 4
    Lol, I want the exact same thing. I like everything about python 3 except the print statement – gunit Apr 07 '17 at 15:37

5 Answers5

14

No, you cannot. The print statement is gone in Python 3; the compiler doesn't support it anymore.

You can make print() work like a function in Python 2; put this at the top of every module that uses print:

from __future__ import print_function

This will remove support for the print statement in Python 2 just like it is gone in Python 3, and you can use the print() function that ships with Python 2.

six can only help bridge code written with both Python 2 and 3 in mind; that includes replacing print statements with print() functions first.

You probably want to read the Porting Python 2 Code to Python 3 howto; it'll tell you about more such from __future__ imports as well, as well as introduce tools such as Modernize and Futurize that can help automate fixing Python 2 code to work on both Python 2 and 3.

Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997
  • 4
    That's a shame - I need to execute code provided by a third party and I really do not like going over all the code changing all those prints :/. (What you describe here is the opposite of my problem: I DO work in python 3, but I need to run code written by people who work in python 2) – paul23 Mar 06 '15 at 10:25
  • 1
    @paul23: sorry, wrong tool. You should try to use the [`2to3` utility](https://docs.python.org/2/library/2to3.html) to fix up the Python 2 code automatically. – Martijn Pieters Mar 06 '15 at 10:32
  • 1
    @paul23 if you're **really** interested in python's statements and keyword mechanics, you might enjoy reading [this](http://mathamy.com/import-accio-bootstrapping-python-grammar.html) article. – OzTamir Mar 06 '15 at 13:48
  • My case is worse...I have some preprocessed data, which contains objects with print statements... A code translator cannot translate member functions of the objects I suppose. – ymeng May 03 '18 at 03:41
  • @ymeng: code translation can handle member functions just fine. – Martijn Pieters May 03 '18 at 06:44
8

You can use a regular expression to replace the print code of Python 2 with Python 3:

Find:
(print) (.*)(\n)

Replace with:
$1($2)$3
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
OliverQ
  • 779
  • 8
  • 6
  • Regular expression in what context? A [Perl](https://en.wikipedia.org/wiki/Perl) script? This will ***not*** work with all flavours of regular expressions. Can you provide an example (by [editing your answer](https://stackoverflow.com/posts/55153675/edit), not here in comments (***without*** "Edit:", "Update:", or similar))? – Peter Mortensen Dec 04 '20 at 07:52
6

You can use the tool 2to3 is an Automated Python 2 to 3 code translation, as @Martijn Pieters♦ told :), you can get over a ride throw the old python and making the changes work into python 3, I make a simple example like this:

I created this file, python2.py:

#!python3

print 5

when I run it with python it obviously shows:

line 3
    print 5          ^
SyntaxError: Missing parentheses in call to 'print'

so, you can transform it via terminal like this:

This is the important comand

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

-w parameter will write the file, if you want only see the future changes without apply them, just run it without -w. after run it it will show something like

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:

And the file will look like:

#!python3

print(5)
Damián Rafael Lattenero
  • 14,625
  • 3
  • 30
  • 62
1

If you are okay with overriding builtins.__import__ and a simple regex to convert the print statements that don't have paren then you can do the following. Note that this doesn't actually change any file, just when you import them it'll read the code into a string, tweak that string, then send the fixed code to the compiler/importer

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

If you save this code to, say, pastimport.py, then lets say I have some file named juniper.py:

def wow(a):
  print a

Now if I want to call juniper.py from python3, I can just do

import pastimport
import juniper

juniper.wow("bean")

And it'll run :)

This could probably be faster and be more like the typical imports with caching and logging and stuff but I don't understand exactly how and when the pyc files are generated yet. There might also be edge cases with c plugins and such I'm not sure. So feel free to suggest improvements, but at least this is a proof of concept. I think you should be able to actually tweak the interpreter inputs and the values of the current file but I'm fiddling with that right now.

Also technically this lets you import any python2 file (2to3 fixes xrange, print, etc.) and if those files import other python2 files they'll be converted too since this overrides the import everyone uses. You can also implement arbitrary operator overloading, require static typing, actually require braces, and technically even import code from other languages or change python altogether with this single import. But I digress

Phylliida
  • 3,667
  • 2
  • 19
  • 31
  • 1
    This is going to try to run 2to3 on everything, whether or not it's actually Python 2 code. – user2357112 supports Monica Nov 07 '17 at 06:13
  • Well 2to3 works fine with python3 code (it just makes no changes), but yes I agree there are lots of edge cases (such as .pyd) this needs to account for. That's pretty easy to do because you can just call the original import function, but I just haven't added the checks here. Ideally it should generate .pyc files as well. Feel free to suggest modifications. – Phylliida Nov 07 '17 at 06:14
  • Try running 2to3 on `print(1, 2)`, and you'll see that it's not safe to run 2to3 on Python 3 code. – user2357112 supports Monica Nov 07 '17 at 06:18
  • I get `(1, 2)` (in the same file that has `print a`) which is exactly what python3 does? Also something like `print(1,2)\nprint('games', end='')` works fine as well – Phylliida Nov 07 '17 at 06:20
  • Hmm nevermind it doesn't (I must have done something wrong in thinking it did work). So you are right, I'm sure some casewise analysis could fix that but it would certainly be much more gross – Phylliida Nov 07 '17 at 06:26
  • Okay I replaced it with a simple regex in theory it should work good now (there may be some edge cases I'm not considering so use at your own risk but this gives you a good start) – Phylliida Nov 07 '17 at 08:03
0

The following snippet works for interactive use. When there is a print syntax error, the script executes the failed command again surrounded with "()" for 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
Peter Bauer
  • 294
  • 2
  • 7