Best way to write Python 2 and 3 compatible code using only the standard library

I am trying to make some of my code compatible with Python 2 and 3.

I am currently struggling with functions like range

/ xrange

and methods like dict.items

/ dict.iteritems

. Ideally, I would like my code to be able to use the former in Python 3.x and the latter in Python 2.x.

Using if

/ else

seems to me to be the easiest way to implement this:

if py >= 3:
    for item in array.items()
    ...
else:
    for item in array.iteritems()

      

However, doing this results in a lot of repetitive and ugly code. Is there a better way to do this using only the standard library ? Can I just indicate somewhere at the beginning of the code to always use range

/ dict.items

if py >= 3

and xrange

/ dict.iteritems

if not?

Can you do something like this?

if py < 3:
    use xrange as range

      

I looked around and I know there are several libraries used to solve this problem, like six futuristic ones). However, I am working on a server that is only running python 2.7 and I am not allowed to install any additional libraries on it. I have python3 code that I would like to use, but I also want to support only one version of the code.

+3


source to share


4 answers


import sys

if sys.version_info.major > 2:
    xrange = range

      

But, as Wim suggests, this basically rewrites six on its own.

And as you can see , six

it does a lot more than processing range

. Just browse the list _moved_attributes

in six sources , for example .



Although Python comes with "batteries included," its standard library is not, and cannot be, comprehensive. And it is not without flaws.

Sometimes there are better batteries out there and it would be useless to use them. Just compare urllib2

with requests

. The latter is much more pleasant to work with.

+3


source


Simple, "Don't make me think!" the solution i am using is to run simple scripts with:

#!/usr/bin/env python
# just make sure that Python 3 code runs fine with 2.7+ too ~98% of the time :)
from __future__ import (division, print_function, absolute_import,
                        unicode_literals)
from builtins import int
try:
    from future_builtins import ascii, filter, hex, map, oct, zip
except:
    pass
import sys
if sys.version_info.major > 2:
    xrange = range

      

(Extra tip to stop most pep8 linters from yelling at you unnecessarily: move the last 3 lines inside and at the top of the block try

above)

But the only case I am using is basically 'shell scripts that were too big and hairy, so I quickly rewrote them in Python and I just want them to run under both Python 2 and 3 with 0 dependencies ". Please DO NOT use this in real application / library code until you know exactly what the implications of all of the above lines are, and if they are sufficient for your use.

Also, "solution" in this case for .iteritems

means "just don't use it", ignore memory optimization and just use instead .items

- if it matters, then you are not writing "0 dependencies just a script", so just choose Python 3 and the code for it (or Python 2 if you need to pretend we're in 2008).



Also, check out these resources to get a proper understanding:


( NOTE: I am answering this already answered question mainly because the accepted answers roughly translate to "you are stupid and this is stupid" and I find it very rude for a SO answer: no question, how dumb question, and how "wrong "to actually answer it, the question deserves a real answer ._

+3


source


I would recommend writing for py2 or py3 in your projects, but not mixing them together and not including any 2/3 checks at all. Your program logic shouldn't care about its python version, except perhaps to avoid functions in built-in objects that conflict.

Instead, import * from your compatibility layer, which fixes the differences between your wireframe and uses shading to make it transparent to your actual project module.

For example, in a compatibility module you can write a Roland Smith substitution for range / xrange, and in your other modules you add "from compatibility import". In this case, each module can use "xrange" and the compatibility level will manage differences 2/3.

Unfortunately, it does not address existing object functions such as dict.iteritems; generally, you will render dict methods harmless, but this is not possible for built-in types (see fooobar.com/questions/68165 / ... ). I can imagine some workarounds:

  • Functional wrappers (essentially Sobolev's answer)
  • Don't use .items () functions at all; use simple loops on the keys and then go to the dictionary with these keys:
    for key in my_dict:
        value = my_dict [key]
        # rest of code goes here
+2


source


I think you are confusing array

and dict

, in this case.

If you are prohibited from using 3rd party libraries for any reason, why not:

def iterate_items(to_iterate):
    if py >= 3:
        return to_iterate.items()
    else:
        return to_iterate.iteritems()

      

And then use it:

for item in iterate_items(your_dict):
    ...

      

0


source







All Articles