On Feb 20, 9:23 am, Florian Ledermann <[email protected]>
wrote:
..
> Maybe this would be an interesting starting point for our Python 3
> coding session next time, he is also documenting some interesting design
> and coding aspects on his blog in the process.
Since it's vaguely relevant, porting python 2 code to python 3
compatible
isn't actually as painful as people generally seem to think. I
converted
Axon (Kamaelia's core concurrency library) to python 3 compatibility
over
the course of one evening last week. The code now runs under both
python
2 and python 3.
Similarly if extension modules have been coded using Pyrex, then
converting them to Cython seems the simplest approach to getting
python 3 compatibility. (Again, this was relatively painless for
the set of python extension bindings I maintain - python-dvb3 etc)
Things I've noted that helps in having a single codebase are:
* Detecting python version by using an import. For example the
Queue module changed name. So you can determine python version
like this:
try:
import Queue as queue
python_version = 2
except ImportError:
import queue
python_version = 3
(This is primarily more useful than using sys.version_info[0]
when you're actually interested in a module that has changed
name of course :-)
* Creating a utility module to alias things like xrange (python2)
and range (python3's version) that changed name to a common name
(I picked vrange) and then using that.
* Converting python2 idioms to python3 ones, again using a utility
library helps. For example, in python 2 you might do this:
def fib():
a,b = 1,1
while 1:
yield a
a,b = b, a+b
>>> g = fib()
>>> g.next()
1
>>> g.next()
1
>>> g.next()
2
In python 3, the way you use generators has changed:
>>> g = fib()
>>> next(g)
1
>>> next(g)
1
>>> next(g)
2
Under the hood, .next has been renamed .__next__, so you can
create a python2 specific version of next to handle this.
* Similarly, if you're creating things with the same API, creating
an aliases for __next__ and next so that the same code runs under
both seems a pragmatic approach.
class MyGen( ...):
def __next__(self):
...
next = __next__
* Some syntactic changes can be dealt with by rewriting code. For
example these two code formats are python 2.5 (and earlier) or
python3 specific:
try: # Python 2.5 and earlier
1/0
except ZeroDivisionError, e:
print("BANG!", e)
try: # Python 3 (Also python 2.6)
1/0
except ZeroDivisionError as e:
print("BANG!", e)
The workaround to have a single piece of code for this is a
little
hacky, but works reliably which looks like this:
try: # Python 3
1/0
except ZeroDivisionError:
e = sys.exc_info()[1]
print("BANG!", e)
It's far from perfect, but works all the way back to python 2.3
(which
I still need to support for example).
* Other changes which are a pain are changes to metaclass syntax
from
this:
class MyBaseObject(object):
__metaclass__ = MyMetaClassType
...
To this:
class MyBaseObject(object, metaclass=MyMetaClassType):
...
The way round this is to use conditional inclusion - to put the
minimal
python 2 version in one file and a minimal python 3 version in
another
file, and then import them into the original file. eg:
import sys
if sys.version_info[0] == 2:
from actual_code_python2 import *
else:
from actual_code_python3 import *
setup.py will get confused by one file or the other depending on
which
version of python you're installing the module under.
* The final thing which I hit was relative imports. In python 2 if
you have a package that looks like this:
setup.py
MyPackage/Foo.py
MyPackage/Bar.py
MyPackage/Baz.py
Then Foo can import Baz by simply doing "import Baz". In python
3,
this changes to "from . import Baz". This breaks under various
versions of python 2. The obvious way round that is to change
all
the imports to absolute imports instead - ie to change Foo's
imports to look like "import MyPackage.Baz as Baz"
That said, once you've made these sorts of changes, they seem
relatively
easy to maintain. The vast bulk of changes I ended up doing were
related
to changing print statements :-)
Michael.
--
To post: [email protected]
To unsubscribe: [email protected]
Feeds: http://groups.google.com/group/python-north-west/feeds
More options: http://groups.google.com/group/python-north-west