Skip to content

Commit eb070aa

Browse files
committed
Update Py2/3 compatibility cheat-sheet
1 parent bec6b4f commit eb070aa

File tree

2 files changed

+78
-58
lines changed

2 files changed

+78
-58
lines changed

docs/compatible_idioms.rst

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ print
5353
5454
# Python 2 and 3:
5555
print('Hello')
56-
5756
To print multiple strings, import ``print_function`` to prevent Py2 from
5857
interpreting it as a tuple:
5958

@@ -64,7 +63,8 @@ interpreting it as a tuple:
6463
.. code:: python
6564
6665
# Python 2 and 3:
67-
from __future__ import print_function
66+
from __future__ import print_function # (at top of module)
67+
6868
print('Hello', 'Guido')
6969
.. code:: python
7070
@@ -73,7 +73,7 @@ interpreting it as a tuple:
7373
.. code:: python
7474
7575
# Python 2 and 3:
76-
from __future__ import print_function # (at top of module)
76+
from __future__ import print_function
7777
7878
print('Hello', file=sys.stderr)
7979
.. code:: python
@@ -83,7 +83,7 @@ interpreting it as a tuple:
8383
.. code:: python
8484
8585
# Python 2 and 3:
86-
from __future__ import print_function # (at top of module)
86+
from __future__ import print_function
8787
8888
print('Hello', end='')
8989
Raising exceptions
@@ -97,18 +97,6 @@ Raising exceptions
9797
9898
# Python 2 and 3:
9999
raise ValueError("dodgy value")
100-
101-
Raising bare string exceptions:
102-
103-
.. code:: python
104-
105-
# Python 2 only:
106-
raise "dodgy value"
107-
.. code:: python
108-
109-
# Python 2 and 3:
110-
raise Exception("dodgy value")
111-
112100
Raising exceptions with a traceback:
113101

114102
.. code:: python
@@ -135,6 +123,40 @@ Raising exceptions with a traceback:
135123
from future.utils import raise_with_traceback
136124
137125
raise_with_traceback(ValueError("dodgy value"))
126+
Exception chaining (PEP 3134):
127+
128+
.. code:: python
129+
130+
# Setup:
131+
class DatabaseError(Exception):
132+
pass
133+
.. code:: python
134+
135+
# Python 3 only
136+
class FileDatabase:
137+
def __init__(self, filename):
138+
try:
139+
self.file = open(filename)
140+
except IOError as exc:
141+
raise DatabaseError('failed to open') from exc
142+
.. code:: python
143+
144+
# Python 2 and 3:
145+
from future.utils import raise_from
146+
147+
class FileDatabase:
148+
def __init__(self, filename):
149+
try:
150+
self.file = open(filename)
151+
except IOError as exc:
152+
raise_from(DatabaseError('failed to open'), exc)
153+
.. code:: python
154+
155+
# Testing the above:
156+
try:
157+
fd = FileDatabase('non_existent_file.txt')
158+
except Exception as e:
159+
assert isinstance(e.__cause__, IOError) # FileNotFoundError on Py3.3+ inherits from IOError
138160
Catching exceptions
139161
~~~~~~~~~~~~~~~~~~~
140162

@@ -165,7 +187,6 @@ Integer division (rounding down):
165187
166188
# Python 2 and 3:
167189
assert 2 // 3 == 0
168-
169190
"True division" (float division):
170191

171192
.. code:: python
@@ -178,7 +199,6 @@ Integer division (rounding down):
178199
from __future__ import division # (at top of module)
179200
180201
assert 3 / 2 == 1.5
181-
182202
"Old division" (i.e. compatible with Py2 behaviour):
183203

184204
.. code:: python
@@ -212,27 +232,29 @@ Short integers are gone in Python 3 and ``long`` has become ``int``
212232
# Python 2 and 3
213233
from future.builtins import int
214234
bigint = int(1)
235+
To test whether a value is an integer (of any kind):
236+
215237
.. code:: python
216238
217239
# Python 2 only:
218240
if isinstance(x, (int, long)):
219-
# ...
241+
...
220242
221243
# Python 3 only:
222244
if isinstance(x, int):
223-
# ...
245+
...
224246
225247
# Python 2 and 3: option 1
226248
from future.builtins import int # subclass of long on Py2
227249
228250
if isinstance(x, int): # matches both int and long on Py2
229-
# ...
251+
...
230252
231253
# Python 2 and 3: option 2
232254
from past.builtins import long
233255
234256
if isinstance(x, (int, long)):
235-
# ...
257+
...
236258
Octal constants
237259
~~~~~~~~~~~~~~~
238260

@@ -300,7 +322,6 @@ prefixes:
300322
# Python 2 and 3
301323
s1 = u'The Zen of Python'
302324
s2 = u'きたないのよりきれいな方がいい\n'
303-
304325
The ``futurize`` and ``python-modernize`` tools do not currently offer
305326
an option to do this automatically.
306327

@@ -314,7 +335,6 @@ this idiom to make all string literals in a module unicode strings:
314335
315336
s1 = 'The Zen of Python'
316337
s2 = 'きたないのよりきれいな方がいい\n'
317-
318338
See http://python-future.org/unicode\_literals.html for more discussion
319339
on which style to use.
320340

@@ -417,7 +437,6 @@ StringIO
417437
# Python 2 and 3:
418438
from io import BytesIO # for handling byte strings
419439
from io import StringIO # for handling unicode strings
420-
421440
Imports relative to a package
422441
-----------------------------
423442

@@ -447,14 +466,12 @@ and the code below is in ``submodule1.py``:
447466
# To make Py2 code safer (more like Py3) by preventing
448467
# implicit relative imports, you can also add this to the top:
449468
from __future__ import absolute_import
450-
451469
Dictionaries
452470
------------
453471

454472
.. code:: python
455473
456474
heights = {'Fred': 175, 'Anne': 166, 'Joe': 192}
457-
458475
Iterating through ``dict`` keys/values/items
459476
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
460477

@@ -464,24 +481,24 @@ Iterable dict keys:
464481
465482
# Python 2 only:
466483
for key in heights.iterkeys():
467-
# ...
484+
...
468485
.. code:: python
469486
470487
# Python 2 and 3:
471488
for key in heights:
472-
# ...
489+
...
473490
Iterable dict values:
474491

475492
.. code:: python
476493
477494
# Python 2 only:
478495
for value in heights.itervalues():
479-
# ...
496+
...
480497
.. code:: python
481498
482499
# Idiomatic Python 3
483500
for value in heights.values(): # extra memory overhead on Py2
484-
# ...
501+
...
485502
.. code:: python
486503
487504
# Python 2 and 3: option 1
@@ -498,20 +515,19 @@ Iterable dict values:
498515
from six import itervalues
499516
500517
for key in itervalues(heights):
501-
# ...
502-
518+
...
503519
Iterable dict items:
504520

505521
.. code:: python
506522
507523
# Python 2 only:
508524
for (key, value) in heights.iteritems():
509-
# ...
525+
...
510526
.. code:: python
511527
512528
# Python 2 and 3: option 1
513529
for (key, value) in heights.items(): # inefficient on Py2
514-
# ...
530+
...
515531
.. code:: python
516532
517533
# Python 2 and 3: option 2
@@ -520,8 +536,7 @@ Iterable dict items:
520536
from six import iteritems
521537
522538
for (key, value) in iteritems(heights):
523-
# ...
524-
539+
...
525540
dict keys/values/items as a list
526541
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
527542

@@ -537,7 +552,6 @@ dict keys as a list:
537552
# Python 2 and 3:
538553
keylist = list(heights)
539554
assert isinstance(keylist, list)
540-
541555
dict values as a list:
542556

543557
.. code:: python
@@ -571,7 +585,6 @@ dict values as a list:
571585
from six import itervalues
572586
573587
valuelist = list(itervalues(heights))
574-
575588
dict items as a list:
576589

577590
.. code:: python
@@ -714,19 +727,19 @@ xrange
714727
715728
# Python 2 only:
716729
for i in xrange(10**8):
717-
# ...
730+
...
718731
.. code:: python
719732
720733
# Python 2 and 3: forward-compatible
721734
from future.builtins import range
722735
for i in range(10**8):
723-
# ...
736+
...
724737
.. code:: python
725738
726739
# Python 2 and 3: backward-compatible
727740
from past.builtins import xrange
728741
for i in xrange(10**8):
729-
# ...
742+
...
730743
range
731744
~~~~~
732745

0 commit comments

Comments
 (0)