A common idiom that I use for Python2-Python3 compatibility is:
try:
from itertools import izip
except ImportError: #python3.x
izip = zip
However, a comment on one of my Stack Overflow answers implies that there may be a better way. Is there a more clean way to accomplish this?
3 Answers 3
Not sure this is really an answer, or I should elaborate on my comment, and in hindsight probably not even a very good comment anyway, but:
Firstly, you can just simplify it to:
try:
from itertools import izip as zip
except ImportError: # will be 3.x series
pass
What I was thinking about was:
From 2.6 you can use as per the docs:
from future_builtins import map # or zip or filter
You do however then have the same problem of ImportError
- so:
try:
from future_builtins import zip
except ImportError: # not 2.6+ or is 3.x
try:
from itertools import izip as zip # < 2.5 or 3.x
except ImportError:
pass
The advantage of using future_builtin
is that it's in effect a bit more "explicit" as to intended behaviour of the module, supported by the language syntax, and possibly recognised by tools. (削除) For instance, I'm not 100% sure, but believe that the 2to3 tool will re-write zip
correctly as list(zip(...
in this case, while a plain zip = izip
may not be... But that's something that needs looking in to. (削除ここまで)
Updated - also in the docs:
The 2to3 tool that ports Python 2 code to Python 3 will recognize this usage and leave the new builtins alone.
-
1\$\begingroup\$ Ahh ... I didn't actually know about
future_builtins
. It seems a little silly that they don't have that in python3 though. I don't know why they didn't do something likefrom __future__ import zip
instead. That would have made sense to me. Anyway, thanks for the explanation. \$\endgroup\$mgilson– mgilson2013年05月17日 01:16:34 +00:00Commented May 17, 2013 at 1:16 -
\$\begingroup\$ I also think it's silly that 2to3 recognizes the usage of
future_builtins
yet leaves thefrom future_builtins import whatever
statement(s) in the output. \$\endgroup\$martineau– martineau2013年06月25日 19:19:53 +00:00Commented Jun 25, 2013 at 19:19
If you are trying to make Python 2.x code compatible with Python 3.x you should look at six:
-
\$\begingroup\$ Yeah,
six
is nice. Generally, if it's simple enough though, I tend to prefer to avoid the extra dependency. \$\endgroup\$mgilson– mgilson2013年05月20日 23:50:25 +00:00Commented May 20, 2013 at 23:50
This is roughly twice as fast as using a try/except:
import itertools
zip = getattr(itertools, 'izip', zip)
-
\$\begingroup\$ I find this claim hard to believe ...
getattr
works by catching theAttributeError
and substituting the default value. Admittedly, that's implemented in C so it might be slightly faster, but I find it hard to believe that there's a factor of 2. I also find it hard to believe that the time would matter in the real world if you have this at the top-level of your module... Finally, this is possibly the cleanest way to write it that I've seen. Kudos for that :-). \$\endgroup\$mgilson– mgilson2017年06月21日 03:28:01 +00:00Commented Jun 21, 2017 at 3:28 -
\$\begingroup\$ @mgilson: Use
timeit
and test it yourself. I thought it might be faster, but I didn't think ~2x. \$\endgroup\$Mike McKerns– Mike McKerns2017年06月22日 11:38:52 +00:00Commented Jun 22, 2017 at 11:38
zip
? I.e.,try: from itertools import izip as zip; except ImportError: pass
. (Please excuse the lack of newlines.) \$\endgroup\$__import__
that I didn't know about or something. \$\endgroup\$