-5

I have the following code which runs fine on python 2 but throws error on python 3

import sys
if sys.version_info > (3,):
  #print("Python 3")
  #Try Block
  except urllib2.HTTPError as err:

else:
  #print "Python 2"  # Throws error on python 3
  #Try Block
  except urllib2.HTTPError, err: # Throws error on python 3.

The above code returns "Python 2" in python 2, but throws syntax error on python 3 (For python 2 syntax ).

Can anyone tell me why is this happening ? And what is the work around to fix those syntax errors in python 3 ?

Note : I am aware of print syntax on Python 3

Thanks you!

Nandan Bhat
  • 1,573
  • 2
  • 9
  • 21
  • python3 needs parens for print... – chris May 02 '17 at 10:06
  • print is a function in python 3. This is among the first things mentioned on any of the zillions of googleable docs and official docs on python 2 / 3 differences. – pvg May 02 '17 at 10:06
  • It's for a migration process from python 2 to python 3. Same code works on python 2 but doesn't work on python 3. – Nandan Bhat May 02 '17 at 10:07
  • 1
    https://docs.python.org/3/howto/pyporting.html – pvg May 02 '17 at 10:09
  • @chris Code works in Python 2 but it's not throwing any errors for `print("Python 3")` . But on Python 3, It's throwing errors for `print("Python 3")`. it's considering as syntax error at this line. I know we have to use parentheses for print on P3 – Nandan Bhat May 02 '17 at 10:17
  • @pvg I am aware of those `zillions of googleable docs`, and I know it's a function on P3. My question is, "Why python 2 doesn't throw any error? and why P3 throws, and what's the work around." Putting parentheses is not gonna work for me, because the code should support both P2 and P3. I hope you have understood my question now ! – Nandan Bhat May 02 '17 at 10:21
  • Possible duplicate of [What does "SyntaxError: Missing parentheses in call to 'print'" mean in Python?](http://stackoverflow.com/questions/25445439/what-does-syntaxerror-missing-parentheses-in-call-to-print-mean-in-python) – mkrieger1 May 02 '17 at 10:21
  • @mkrieger1 It's not a duplicate. I know on P3 print uses parentheses. – Nandan Bhat May 02 '17 at 10:22
  • You have changed your code so that it is no longer valid syntax for any version of Python. You have `except` clauses without any `try` statements. –  May 02 '17 at 18:42
  • @DavidCullen Try catch is not my problem. I changed to to except because people started advising me about print() function in P3. In except P3 has to have "as" but in P2 "," is used instead. I am aware of all those changes. If you know anything that makes a page run in both P2 and P3 without showing any errors, please let me know, Othe than that, nothing is gonna help me :) – Nandan Bhat May 03 '17 at 09:32

2 Answers2

2

The problem is that the parser runs before any code is evaluated at runtime. Your check sys.version_info > (3,) runs at run time, after the code was already parsed and compiled. So doing such checks, you are able to make changes at runtime, but that does not help you when dealing with syntax changes.

The syntax is parsed and compiled before any code is interpreted, that is why you get syntax errors even for code that is never run at runtime.

If you are trying to create a polyglot script that is able to run on both Python 3 and Python 2, then you will need to make sure to use a syntax that works on both. For print in particular, you can import the print function in Python 2, so you can use it just like you would in Python 3:

from __future__ import print_function

Some newer features won’t work that way (for example everything async), but for the most part, you can make it work somehow.

If you end up depending on stuff with Python 3 that requires Python 2-incompatible syntax, then you could put that into a separate module and import that module conditionally at runtime. That way it won’t be loaded for Python 2, so the Python 2 parser wouldn’t attempt to load the incompatible syntax.


As for why Python 2 does not throw an error, that’s actually very simple: print('foo bar') is valid syntax in Python 2, even with the print statement. That is because you can put parentheses around anything without impacting the value. So what you actually do there is this:

print ('foo bar')
^^^^^
print statement
      ^^^^^^^^^^^
      value, wrapped in parentheses (that don’t do anything)

That’s also the reason, why the following produces different results in Python 3 and 2:

print('foo', 'bar')

In Python 3, you get foo bar as the output, while Python 2 gives you ('foo', 'bar'). That is because the comma inside the parentheses now makes this a tuple, so you pass a tuple to the print statement. – Importing the print function fixes this to give you the same behavior on Python 2 as on Python 3.

poke
  • 369,085
  • 72
  • 557
  • 602
  • Understood ! Thanks for explaining. What if I want to import some libraries/classes instead of print statement. ? – Nandan Bhat May 02 '17 at 10:28
  • `As for why Python 2 does not throw an error, that’s actually very simple: print('foo bar') is valid syntax in Python 2, even with the print statement. That is because you can put parentheses around anything without impacting the value. So what you actually do there is this:` +1 For this – Nandan Bhat May 02 '17 at 10:28
  • Importing is a process that happens at runtime, so you can easily make that conditional on the version. – poke May 02 '17 at 10:29
  • I am getting error for this line `except urllib2.HTTPError, err:` while executing on P3. I know that it has to be `except urllib2.HTTPError as err:` on P3, but `except urllib2.HTTPError, err:` should execute only if it's P2. I used print example only to make the question short. – Nandan Bhat May 02 '17 at 10:38
  • `except` is again a syntax feature, so you will have to use the syntax that works for both. So use `as`. – poke May 02 '17 at 11:03
  • So there will be some other lines of codes which are isolated. Like which works on P2 doesn't work on P3, and vice versa. How to handle them. Code of both the vesrions should be present in the same page. And it should be switched according to the condition(Python Version of the machine) – Nandan Bhat May 02 '17 at 11:07
  • Again: You cannot do this for syntax features; you can only use runtime evaluations for runtime expressions. – poke May 02 '17 at 11:26
1

Even though the line print "Python 2" will never be executed in Python 3, it will still be compiled to byte code (or at least attempted). That line is a syntax error in Python 3, which requires the printed items to be in parentheses. Look up the documentation for more details: other changes to print were also made.

So remove the error. Make the line

print("Python 2")  # Throws error on python 3

instead. That way it works in both Python 2 and in 3. There are many sites that discuss how to write code that executes in both versions of Python. The parentheses are merely ignored in version 2 but are needed in version 3. This works if you print only one item: more than one gets more complicated.

There is another way to do printing in both versions, using from __future__ import print_function but the way I showed is easier.

Note that your attempted comment in the line is also not proper Python syntax. Change the // to # and it works.

Rory Daulton
  • 21,934
  • 6
  • 42
  • 50
  • Makes more sense than all other comments. But I want to keep both the blocks, as it's an application that should support both Python 2 and Python 3. – Nandan Bhat May 02 '17 at 10:14
  • @Nandan: One of my points was that putting both print statements in parentheses, when printing one only item per print command, works in both versions of Python. Did you try it? If by "keep both the blocks" you mean make no modifications at all to the code, I do not see how that is possible. Did you also change the comment style to `#` or remove the comment? – Rory Daulton May 02 '17 at 10:18
  • @nandan: If you put `from __future__ import print_function`, then Python 2 can have print as a function and Python 3 will not be changed. – zondo May 02 '17 at 10:30
  • Understood ! Thanks for explaining. What if I want to import some libraries/classes instead of print statement. ? – Nandan Bhat May 02 '17 at 10:32
  • I am getting error for this line `except urllib2.HTTPError, err:` while executing on P3. I know that it has to be `except urllib2.HTTPError as err:` on P3, but `except urllib2.HTTPError, err:` should execute only if it's P2. I used print example only to make the question short. – Nandan Bhat May 02 '17 at 10:38
  • @Nandan: Libraries and classes are more difficult. Usually you have to search the documentation to see which versions of Python are compatible with the library. Many libraries only support only Python 2 or Python, 3, and some support only some sub-versions of those versions. – Rory Daulton May 02 '17 at 12:29
  • @Nandan: [Python 2's documentation for urllib2](https://docs.python.org/2/library/urllib2.html) says this: "The [urllib2](https://docs.python.org/2/library/urllib2.html#module-urllib2) module has been split across several modules in Python 3 named **urllib.request** and **urllib.error**. The [2to3](https://docs.python.org/2/glossary.html#term-2to3) tool will automatically adapt imports when converting your sources to Python 3." So use `2to3` or manually do the equivalent. Making code to work in both versions will be difficult. – Rory Daulton May 02 '17 at 12:46
  • Thank you so much ! – Nandan Bhat May 02 '17 at 12:48