3. Loads of goodies!
● print is a function
● All strings are unicode
● Binary data handled by new bytes type
● dict.keys/items/values() are generators
● Integers are all long
● 3/2 == 1.5
● The standard library is reorganized
● New easter egg
5. Only support Python 3
● For end-user software and systems
● Run 2to3 once
● Then fix the code until it works.
● Done!
6. Separate branches
● For stable python modules
● If you only do bugfixes
● Make a branch for the old version
● Run 2to3 once
● Fix until it works
● Bug fix both branches
7. How to distribute
● Separate package names on pypi
● Add a warning and error in the setup.py:
“For Python 2 support, please use version
3.x of MyCoolModule”
● Only release binary eggs (bdist_egg)
● Include both src2/ and src3/ and have
different setup() parameters for different
Python versions.
8. Continuous conversion with 2to3
● If you need to support Python 2 and Python
3 and the code is changing a lot
● Keep developing in Python 2
● Convert to Python 3 for testing and install
● Only one source distribution
● Compatibility hacks may be needed
9. Solution: Distribute!
● Very little work to set up 2to3 support
● Runs 2to3 on testing and installing:
– Only one source tree
– Only one distribution
11. Single code base; no conversion
● If 2to3 for some reason is infeasible
● Support Python 2 and Python 3 from the
same code without 2to3
● No distribution worries!
● Loads of compatibility hacks
● Fun, but ugly!
12. When?
● For end-user systems: When you feel like it
● For modules: As soon as you can
● I.e. when your dependencies do
26. Wrapper class for Python 2
class bites(str):
def __new__(cls, value):
if isinstance(value[0], int):
# It's a list of integers
value = ''.join([chr(x) for x in value])
return super(bites, cls).__new__(cls, value)
def itemint(self, index):
return ord(self[index])
def iterint(self):
for x in self:
yield ord(x)
27. Wrapper class for Python 3
class bites(bytes):
def __new__(cls, value):
if isinstance(value, str):
# It's a unicode string:
value = value.encode('ISO-8859-1')
return super(bites, cls).__new__(cls, value)
def itemint(self, x):
return self[x]
def iterint(self):
for x in self:
yield x
28. Usage
>>> from bites import bites
>>> bites('GIF89a').itemint(2)
70
>>> for x in bites('GIF89a').iterint():
... print(x),
71 73 70 56 57 97
29. Mixed/unknown files
● Open in binary mode, and decode
>>> data = open('maybe_a.gif', 'rb').read()
>>> if data[:6] != bites('GIF89a'):
... str = data.decode('Latin-1')
30. Unorderable types
● Many built in types that were comparable
now are not
● __cmp__ is no longer supported
32. Doctests
● Binary data now is a b'' literal
● Unicode data no longer has the u''
● Classes and types have often changed
names or at least __repr__
● Exceptions are formated differently as a
result, and exception matching doesn't
work under both versions.
33. Test with ==
Go from:
>>> myfunction()
u'Foobar'
To:
>>> myfunction() == u'Foobar'
True
36. Workaround for stdlib reorg
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
37. Workaround for except:
● Python 2:
except Exception, e:
● Python 3:
except Exception as e:
● Both:
except Exception:
e = sys.exc_info[1]
38. Workaround for print()
● For simple print cases:
print(“Something”) works everywhere.
print(“Something”, “else”) doesn't.
● Make your own print function!
46. Use iterator methods
Instead of
{}.keys(), {}.values(), {}.items()
Use
{}.iterkeys(), {}.itervalues(), {}.iteritems()
47. Use iterator methods
● In Python 3, {}.keys(), {}.values(),
{}.items() are iterators
● 2to3 wraps them in list(), so d.values()
becomes list(d.values())
● By explicitly using iterators in Python 2
code, you avoid the list()
48. Put an in in it
● Old: adict.has_key(foo)
● New: foo in adict
50. 2 * 3 = Six
● A module to help with compatibility
● Several compatibility methods:
– b()
– print_()
– etc...
● Tons of helpful constants:
– integer_types
– string_types
– etc...