1.. _compatible-idioms: 2 3Cheat Sheet: Writing Python 2-3 compatible code 4=============================================== 5 6- **Copyright (c):** 2013-2019 Python Charmers Pty Ltd, Australia. 7- **Author:** Ed Schofield. 8- **Licence:** Creative Commons Attribution. 9 10A PDF version is here: http://python-future.org/compatible\_idioms.pdf 11 12This notebook shows you idioms for writing future-proof code that is 13compatible with both versions of Python: 2 and 3. It accompanies Ed 14Schofield's talk at PyCon AU 2014, "Writing 2/3 compatible code". (The 15video is here: http://www.youtube.com/watch?v=KOqk8j11aAI&t=10m14s.) 16 17Minimum versions: 18 19- Python 2: 2.7+ 20- Python 3: 3.4+ 21 22Setup 23----- 24 25The imports below refer to these ``pip``-installable packages on PyPI: 26 27:: 28 29 import future # pip install future 30 import builtins # pip install future 31 import past # pip install future 32 import six # pip install six 33 34The following scripts are also ``pip``-installable: 35 36:: 37 38 futurize # pip install future 39 pasteurize # pip install future 40 41See http://python-future.org and https://pythonhosted.org/six/ for more 42information. 43 44Essential syntax differences 45---------------------------- 46 47print 48~~~~~ 49 50.. code:: python 51 52 # Python 2 only: 53 print 'Hello' 54.. code:: python 55 56 # Python 2 and 3: 57 print('Hello') 58To print multiple strings, import ``print_function`` to prevent Py2 from 59interpreting it as a tuple: 60 61.. code:: python 62 63 # Python 2 only: 64 print 'Hello', 'Guido' 65.. code:: python 66 67 # Python 2 and 3: 68 from __future__ import print_function # (at top of module) 69 70 print('Hello', 'Guido') 71.. code:: python 72 73 # Python 2 only: 74 print >> sys.stderr, 'Hello' 75.. code:: python 76 77 # Python 2 and 3: 78 from __future__ import print_function 79 80 print('Hello', file=sys.stderr) 81.. code:: python 82 83 # Python 2 only: 84 print 'Hello', 85.. code:: python 86 87 # Python 2 and 3: 88 from __future__ import print_function 89 90 print('Hello', end='') 91Raising exceptions 92~~~~~~~~~~~~~~~~~~ 93 94.. code:: python 95 96 # Python 2 only: 97 raise ValueError, "dodgy value" 98.. code:: python 99 100 # Python 2 and 3: 101 raise ValueError("dodgy value") 102Raising exceptions with a traceback: 103 104.. code:: python 105 106 # Python 2 only: 107 traceback = sys.exc_info()[2] 108 raise ValueError, "dodgy value", traceback 109.. code:: python 110 111 # Python 3 only: 112 raise ValueError("dodgy value").with_traceback() 113.. code:: python 114 115 # Python 2 and 3: option 1 116 from six import reraise as raise_ 117 # or 118 from future.utils import raise_ 119 120 traceback = sys.exc_info()[2] 121 raise_(ValueError, "dodgy value", traceback) 122.. code:: python 123 124 # Python 2 and 3: option 2 125 from future.utils import raise_with_traceback 126 127 raise_with_traceback(ValueError("dodgy value")) 128Exception chaining (PEP 3134): 129 130.. code:: python 131 132 # Setup: 133 class DatabaseError(Exception): 134 pass 135.. code:: python 136 137 # Python 3 only 138 class FileDatabase: 139 def __init__(self, filename): 140 try: 141 self.file = open(filename) 142 except IOError as exc: 143 raise DatabaseError('failed to open') from exc 144.. code:: python 145 146 # Python 2 and 3: 147 from future.utils import raise_from 148 149 class FileDatabase: 150 def __init__(self, filename): 151 try: 152 self.file = open(filename) 153 except IOError as exc: 154 raise_from(DatabaseError('failed to open'), exc) 155.. code:: python 156 157 # Testing the above: 158 try: 159 fd = FileDatabase('non_existent_file.txt') 160 except Exception as e: 161 assert isinstance(e.__cause__, IOError) # FileNotFoundError on Py3.3+ inherits from IOError 162Catching exceptions 163~~~~~~~~~~~~~~~~~~~ 164 165.. code:: python 166 167 # Python 2 only: 168 try: 169 ... 170 except ValueError, e: 171 ... 172.. code:: python 173 174 # Python 2 and 3: 175 try: 176 ... 177 except ValueError as e: 178 ... 179Division 180~~~~~~~~ 181 182Integer division (rounding down): 183 184.. code:: python 185 186 # Python 2 only: 187 assert 2 / 3 == 0 188.. code:: python 189 190 # Python 2 and 3: 191 assert 2 // 3 == 0 192"True division" (float division): 193 194.. code:: python 195 196 # Python 3 only: 197 assert 3 / 2 == 1.5 198.. code:: python 199 200 # Python 2 and 3: 201 from __future__ import division # (at top of module) 202 203 assert 3 / 2 == 1.5 204"Old division" (i.e. compatible with Py2 behaviour): 205 206.. code:: python 207 208 # Python 2 only: 209 a = b / c # with any types 210.. code:: python 211 212 # Python 2 and 3: 213 from past.utils import old_div 214 215 a = old_div(b, c) # always same as / on Py2 216Long integers 217~~~~~~~~~~~~~ 218 219Short integers are gone in Python 3 and ``long`` has become ``int`` 220(without the trailing ``L`` in the ``repr``). 221 222.. code:: python 223 224 # Python 2 only 225 k = 9223372036854775808L 226 227 # Python 2 and 3: 228 k = 9223372036854775808 229.. code:: python 230 231 # Python 2 only 232 bigint = 1L 233 234 # Python 2 and 3 235 from builtins import int 236 bigint = int(1) 237To test whether a value is an integer (of any kind): 238 239.. code:: python 240 241 # Python 2 only: 242 if isinstance(x, (int, long)): 243 ... 244 245 # Python 3 only: 246 if isinstance(x, int): 247 ... 248 249 # Python 2 and 3: option 1 250 from builtins import int # subclass of long on Py2 251 252 if isinstance(x, int): # matches both int and long on Py2 253 ... 254 255 # Python 2 and 3: option 2 256 from past.builtins import long 257 258 if isinstance(x, (int, long)): 259 ... 260Octal constants 261~~~~~~~~~~~~~~~ 262 263.. code:: python 264 265 0644 # Python 2 only 266.. code:: python 267 268 0o644 # Python 2 and 3 269Backtick repr 270~~~~~~~~~~~~~ 271 272.. code:: python 273 274 `x` # Python 2 only 275.. code:: python 276 277 repr(x) # Python 2 and 3 278Metaclasses 279~~~~~~~~~~~ 280 281.. code:: python 282 283 class BaseForm(object): 284 pass 285 286 class FormType(type): 287 pass 288.. code:: python 289 290 # Python 2 only: 291 class Form(BaseForm): 292 __metaclass__ = FormType 293 pass 294.. code:: python 295 296 # Python 3 only: 297 class Form(BaseForm, metaclass=FormType): 298 pass 299.. code:: python 300 301 # Python 2 and 3: 302 from six import with_metaclass 303 # or 304 from future.utils import with_metaclass 305 306 class Form(with_metaclass(FormType, BaseForm)): 307 pass 308Strings and bytes 309----------------- 310 311Unicode (text) string literals 312~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 313 314If you are upgrading an existing Python 2 codebase, it may be preferable 315to mark up all string literals as unicode explicitly with ``u`` 316prefixes: 317 318.. code:: python 319 320 # Python 2 only 321 s1 = 'The Zen of Python' 322 s2 = u'きたないのよりきれいな方がいい\n' 323 324 # Python 2 and 3 325 s1 = u'The Zen of Python' 326 s2 = u'きたないのよりきれいな方がいい\n' 327The ``futurize`` and ``python-modernize`` tools do not currently offer 328an option to do this automatically. 329 330If you are writing code for a new project or new codebase, you can use 331this idiom to make all string literals in a module unicode strings: 332 333.. code:: python 334 335 # Python 2 and 3 336 from __future__ import unicode_literals # at top of module 337 338 s1 = 'The Zen of Python' 339 s2 = 'きたないのよりきれいな方がいい\n' 340See http://python-future.org/unicode\_literals.html for more discussion 341on which style to use. 342 343Byte-string literals 344~~~~~~~~~~~~~~~~~~~~ 345 346.. code:: python 347 348 # Python 2 only 349 s = 'This must be a byte-string' 350 351 # Python 2 and 3 352 s = b'This must be a byte-string' 353To loop over a byte-string with possible high-bit characters, obtaining 354each character as a byte-string of length 1: 355 356.. code:: python 357 358 # Python 2 only: 359 for bytechar in 'byte-string with high-bit chars like \xf9': 360 ... 361 362 # Python 3 only: 363 for myint in b'byte-string with high-bit chars like \xf9': 364 bytechar = bytes([myint]) 365 366 # Python 2 and 3: 367 from builtins import bytes 368 for myint in bytes(b'byte-string with high-bit chars like \xf9'): 369 bytechar = bytes([myint]) 370As an alternative, ``chr()`` and ``.encode('latin-1')`` can be used to 371convert an int into a 1-char byte string: 372 373.. code:: python 374 375 # Python 3 only: 376 for myint in b'byte-string with high-bit chars like \xf9': 377 char = chr(myint) # returns a unicode string 378 bytechar = char.encode('latin-1') 379 380 # Python 2 and 3: 381 from builtins import bytes, chr 382 for myint in bytes(b'byte-string with high-bit chars like \xf9'): 383 char = chr(myint) # returns a unicode string 384 bytechar = char.encode('latin-1') # forces returning a byte str 385basestring 386~~~~~~~~~~ 387 388.. code:: python 389 390 # Python 2 only: 391 a = u'abc' 392 b = 'def' 393 assert (isinstance(a, basestring) and isinstance(b, basestring)) 394 395 # Python 2 and 3: alternative 1 396 from past.builtins import basestring # pip install future 397 398 a = u'abc' 399 b = b'def' 400 assert (isinstance(a, basestring) and isinstance(b, basestring)) 401.. code:: python 402 403 # Python 2 and 3: alternative 2: refactor the code to avoid considering 404 # byte-strings as strings. 405 406 from builtins import str 407 a = u'abc' 408 b = b'def' 409 c = b.decode() 410 assert isinstance(a, str) and isinstance(c, str) 411 # ... 412unicode 413~~~~~~~ 414 415.. code:: python 416 417 # Python 2 only: 418 templates = [u"blog/blog_post_detail_%s.html" % unicode(slug)] 419.. code:: python 420 421 # Python 2 and 3: alternative 1 422 from builtins import str 423 templates = [u"blog/blog_post_detail_%s.html" % str(slug)] 424.. code:: python 425 426 # Python 2 and 3: alternative 2 427 from builtins import str as text 428 templates = [u"blog/blog_post_detail_%s.html" % text(slug)] 429StringIO 430~~~~~~~~ 431 432.. code:: python 433 434 # Python 2 only: 435 from StringIO import StringIO 436 # or: 437 from cStringIO import StringIO 438 439 # Python 2 and 3: 440 from io import BytesIO # for handling byte strings 441 from io import StringIO # for handling unicode strings 442Imports relative to a package 443----------------------------- 444 445Suppose the package is: 446 447:: 448 449 mypackage/ 450 __init__.py 451 submodule1.py 452 submodule2.py 453 454 455and the code below is in ``submodule1.py``: 456 457.. code:: python 458 459 # Python 2 only: 460 import submodule2 461.. code:: python 462 463 # Python 2 and 3: 464 from . import submodule2 465.. code:: python 466 467 # Python 2 and 3: 468 # To make Py2 code safer (more like Py3) by preventing 469 # implicit relative imports, you can also add this to the top: 470 from __future__ import absolute_import 471Dictionaries 472------------ 473 474.. code:: python 475 476 heights = {'Fred': 175, 'Anne': 166, 'Joe': 192} 477Iterating through ``dict`` keys/values/items 478~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 479 480Iterable dict keys: 481 482.. code:: python 483 484 # Python 2 only: 485 for key in heights.iterkeys(): 486 ... 487.. code:: python 488 489 # Python 2 and 3: 490 for key in heights: 491 ... 492Iterable dict values: 493 494.. code:: python 495 496 # Python 2 only: 497 for value in heights.itervalues(): 498 ... 499.. code:: python 500 501 # Idiomatic Python 3 502 for value in heights.values(): # extra memory overhead on Py2 503 ... 504.. code:: python 505 506 # Python 2 and 3: option 1 507 from builtins import dict 508 509 heights = dict(Fred=175, Anne=166, Joe=192) 510 for key in heights.values(): # efficient on Py2 and Py3 511 ... 512.. code:: python 513 514 # Python 2 and 3: option 2 515 from future.utils import itervalues 516 # or 517 from six import itervalues 518 519 for key in itervalues(heights): 520 ... 521Iterable dict items: 522 523.. code:: python 524 525 # Python 2 only: 526 for (key, value) in heights.iteritems(): 527 ... 528.. code:: python 529 530 # Python 2 and 3: option 1 531 for (key, value) in heights.items(): # inefficient on Py2 532 ... 533.. code:: python 534 535 # Python 2 and 3: option 2 536 from future.utils import viewitems 537 538 for (key, value) in viewitems(heights): # also behaves like a set 539 ... 540.. code:: python 541 542 # Python 2 and 3: option 3 543 from future.utils import iteritems 544 # or 545 from six import iteritems 546 547 for (key, value) in iteritems(heights): 548 ... 549dict keys/values/items as a list 550~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 551 552dict keys as a list: 553 554.. code:: python 555 556 # Python 2 only: 557 keylist = heights.keys() 558 assert isinstance(keylist, list) 559.. code:: python 560 561 # Python 2 and 3: 562 keylist = list(heights) 563 assert isinstance(keylist, list) 564dict values as a list: 565 566.. code:: python 567 568 # Python 2 only: 569 heights = {'Fred': 175, 'Anne': 166, 'Joe': 192} 570 valuelist = heights.values() 571 assert isinstance(valuelist, list) 572.. code:: python 573 574 # Python 2 and 3: option 1 575 valuelist = list(heights.values()) # inefficient on Py2 576.. code:: python 577 578 # Python 2 and 3: option 2 579 from builtins import dict 580 581 heights = dict(Fred=175, Anne=166, Joe=192) 582 valuelist = list(heights.values()) 583.. code:: python 584 585 # Python 2 and 3: option 3 586 from future.utils import listvalues 587 588 valuelist = listvalues(heights) 589.. code:: python 590 591 # Python 2 and 3: option 4 592 from future.utils import itervalues 593 # or 594 from six import itervalues 595 596 valuelist = list(itervalues(heights)) 597dict items as a list: 598 599.. code:: python 600 601 # Python 2 and 3: option 1 602 itemlist = list(heights.items()) # inefficient on Py2 603.. code:: python 604 605 # Python 2 and 3: option 2 606 from future.utils import listitems 607 608 itemlist = listitems(heights) 609.. code:: python 610 611 # Python 2 and 3: option 3 612 from future.utils import iteritems 613 # or 614 from six import iteritems 615 616 itemlist = list(iteritems(heights)) 617Custom class behaviour 618---------------------- 619 620Custom iterators 621~~~~~~~~~~~~~~~~ 622 623.. code:: python 624 625 # Python 2 only 626 class Upper(object): 627 def __init__(self, iterable): 628 self._iter = iter(iterable) 629 def next(self): # Py2-style 630 return self._iter.next().upper() 631 def __iter__(self): 632 return self 633 634 itr = Upper('hello') 635 assert itr.next() == 'H' # Py2-style 636 assert list(itr) == list('ELLO') 637.. code:: python 638 639 # Python 2 and 3: option 1 640 from builtins import object 641 642 class Upper(object): 643 def __init__(self, iterable): 644 self._iter = iter(iterable) 645 def __next__(self): # Py3-style iterator interface 646 return next(self._iter).upper() # builtin next() function calls 647 def __iter__(self): 648 return self 649 650 itr = Upper('hello') 651 assert next(itr) == 'H' # compatible style 652 assert list(itr) == list('ELLO') 653.. code:: python 654 655 # Python 2 and 3: option 2 656 from future.utils import implements_iterator 657 658 @implements_iterator 659 class Upper(object): 660 def __init__(self, iterable): 661 self._iter = iter(iterable) 662 def __next__(self): # Py3-style iterator interface 663 return next(self._iter).upper() # builtin next() function calls 664 def __iter__(self): 665 return self 666 667 itr = Upper('hello') 668 assert next(itr) == 'H' 669 assert list(itr) == list('ELLO') 670Custom ``__str__`` methods 671~~~~~~~~~~~~~~~~~~~~~~~~~~ 672 673.. code:: python 674 675 # Python 2 only: 676 class MyClass(object): 677 def __unicode__(self): 678 return 'Unicode string: \u5b54\u5b50' 679 def __str__(self): 680 return unicode(self).encode('utf-8') 681 682 a = MyClass() 683 print(a) # prints encoded string 684.. code:: python 685 686 # Python 2 and 3: 687 from future.utils import python_2_unicode_compatible 688 689 @python_2_unicode_compatible 690 class MyClass(object): 691 def __str__(self): 692 return u'Unicode string: \u5b54\u5b50' 693 694 a = MyClass() 695 print(a) # prints string encoded as utf-8 on Py2 696 697.. parsed-literal:: 698 699 Unicode string: 孔子 700 701 702Custom ``__nonzero__`` vs ``__bool__`` method: 703~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 704 705.. code:: python 706 707 # Python 2 only: 708 class AllOrNothing(object): 709 def __init__(self, l): 710 self.l = l 711 def __nonzero__(self): 712 return all(self.l) 713 714 container = AllOrNothing([0, 100, 200]) 715 assert not bool(container) 716.. code:: python 717 718 # Python 2 and 3: 719 from builtins import object 720 721 class AllOrNothing(object): 722 def __init__(self, l): 723 self.l = l 724 def __bool__(self): 725 return all(self.l) 726 727 container = AllOrNothing([0, 100, 200]) 728 assert not bool(container) 729Lists versus iterators 730---------------------- 731 732xrange 733~~~~~~ 734 735.. code:: python 736 737 # Python 2 only: 738 for i in xrange(10**8): 739 ... 740.. code:: python 741 742 # Python 2 and 3: forward-compatible 743 from builtins import range 744 for i in range(10**8): 745 ... 746.. code:: python 747 748 # Python 2 and 3: backward-compatible 749 from past.builtins import xrange 750 for i in xrange(10**8): 751 ... 752range 753~~~~~ 754 755.. code:: python 756 757 # Python 2 only 758 mylist = range(5) 759 assert mylist == [0, 1, 2, 3, 4] 760.. code:: python 761 762 # Python 2 and 3: forward-compatible: option 1 763 mylist = list(range(5)) # copies memory on Py2 764 assert mylist == [0, 1, 2, 3, 4] 765.. code:: python 766 767 # Python 2 and 3: forward-compatible: option 2 768 from builtins import range 769 770 mylist = list(range(5)) 771 assert mylist == [0, 1, 2, 3, 4] 772.. code:: python 773 774 # Python 2 and 3: option 3 775 from future.utils import lrange 776 777 mylist = lrange(5) 778 assert mylist == [0, 1, 2, 3, 4] 779.. code:: python 780 781 # Python 2 and 3: backward compatible 782 from past.builtins import range 783 784 mylist = range(5) 785 assert mylist == [0, 1, 2, 3, 4] 786map 787~~~ 788 789.. code:: python 790 791 # Python 2 only: 792 mynewlist = map(f, myoldlist) 793 assert mynewlist == [f(x) for x in myoldlist] 794.. code:: python 795 796 # Python 2 and 3: option 1 797 # Idiomatic Py3, but inefficient on Py2 798 mynewlist = list(map(f, myoldlist)) 799 assert mynewlist == [f(x) for x in myoldlist] 800.. code:: python 801 802 # Python 2 and 3: option 2 803 from builtins import map 804 805 mynewlist = list(map(f, myoldlist)) 806 assert mynewlist == [f(x) for x in myoldlist] 807.. code:: python 808 809 # Python 2 and 3: option 3 810 try: 811 import itertools.imap as map 812 except ImportError: 813 pass 814 815 mynewlist = list(map(f, myoldlist)) # inefficient on Py2 816 assert mynewlist == [f(x) for x in myoldlist] 817.. code:: python 818 819 # Python 2 and 3: option 4 820 from future.utils import lmap 821 822 mynewlist = lmap(f, myoldlist) 823 assert mynewlist == [f(x) for x in myoldlist] 824.. code:: python 825 826 # Python 2 and 3: option 5 827 from past.builtins import map 828 829 mynewlist = map(f, myoldlist) 830 assert mynewlist == [f(x) for x in myoldlist] 831imap 832~~~~ 833 834.. code:: python 835 836 # Python 2 only: 837 from itertools import imap 838 839 myiter = imap(func, myoldlist) 840 assert isinstance(myiter, iter) 841.. code:: python 842 843 # Python 3 only: 844 myiter = map(func, myoldlist) 845 assert isinstance(myiter, iter) 846.. code:: python 847 848 # Python 2 and 3: option 1 849 from builtins import map 850 851 myiter = map(func, myoldlist) 852 assert isinstance(myiter, iter) 853.. code:: python 854 855 # Python 2 and 3: option 2 856 try: 857 import itertools.imap as map 858 except ImportError: 859 pass 860 861 myiter = map(func, myoldlist) 862 assert isinstance(myiter, iter) 863.. code:: python 864 865 # Python 2 and 3: option 3 866 from six.moves import map 867 868 myiter = map(func, myoldlist) 869 assert isinstance(myiter, iter) 870 871zip, izip 872~~~~~~~~~ 873 874As above with ``zip`` and ``itertools.izip``. 875 876filter, ifilter 877~~~~~~~~~~~~~~~ 878 879As above with ``filter`` and ``itertools.ifilter`` too. 880 881Other builtins 882-------------- 883 884File IO with open() 885~~~~~~~~~~~~~~~~~~~ 886 887.. code:: python 888 889 # Python 2 only 890 f = open('myfile.txt') 891 data = f.read() # as a byte string 892 text = data.decode('utf-8') 893 894 # Python 2 and 3: alternative 1 895 from io import open 896 f = open('myfile.txt', 'rb') 897 data = f.read() # as bytes 898 text = data.decode('utf-8') # unicode, not bytes 899 900 # Python 2 and 3: alternative 2 901 from io import open 902 f = open('myfile.txt', encoding='utf-8') 903 text = f.read() # unicode, not bytes 904reduce() 905~~~~~~~~ 906 907.. code:: python 908 909 # Python 2 only: 910 assert reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) == 1+2+3+4+5 911.. code:: python 912 913 # Python 2 and 3: 914 from functools import reduce 915 916 assert reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) == 1+2+3+4+5 917raw\_input() 918~~~~~~~~~~~~ 919 920.. code:: python 921 922 # Python 2 only: 923 name = raw_input('What is your name? ') 924 assert isinstance(name, str) # native str 925.. code:: python 926 927 # Python 2 and 3: 928 from builtins import input 929 930 name = input('What is your name? ') 931 assert isinstance(name, str) # native str on Py2 and Py3 932input() 933~~~~~~~ 934 935.. code:: python 936 937 # Python 2 only: 938 input("Type something safe please: ") 939.. code:: python 940 941 # Python 2 and 3 942 from builtins import input 943 eval(input("Type something safe please: ")) 944Warning: using either of these is **unsafe** with untrusted input. 945 946file() 947~~~~~~ 948 949.. code:: python 950 951 # Python 2 only: 952 f = file(pathname) 953.. code:: python 954 955 # Python 2 and 3: 956 f = open(pathname) 957 958 # But preferably, use this: 959 from io import open 960 f = open(pathname, 'rb') # if f.read() should return bytes 961 # or 962 f = open(pathname, 'rt') # if f.read() should return unicode text 963exec 964~~~~ 965 966.. code:: python 967 968 # Python 2 only: 969 exec 'x = 10' 970 971 # Python 2 and 3: 972 exec('x = 10') 973.. code:: python 974 975 # Python 2 only: 976 g = globals() 977 exec 'x = 10' in g 978 979 # Python 2 and 3: 980 g = globals() 981 exec('x = 10', g) 982.. code:: python 983 984 # Python 2 only: 985 l = locals() 986 exec 'x = 10' in g, l 987 988 # Python 2 and 3: 989 exec('x = 10', g, l) 990execfile() 991~~~~~~~~~~ 992 993.. code:: python 994 995 # Python 2 only: 996 execfile('myfile.py') 997.. code:: python 998 999 # Python 2 and 3: alternative 1 1000 from past.builtins import execfile 1001 1002 execfile('myfile.py') 1003.. code:: python 1004 1005 # Python 2 and 3: alternative 2 1006 exec(compile(open('myfile.py').read())) 1007 1008 # This can sometimes cause this: 1009 # SyntaxError: function ... uses import * and bare exec ... 1010 # See https://github.com/PythonCharmers/python-future/issues/37 1011unichr() 1012~~~~~~~~ 1013 1014.. code:: python 1015 1016 # Python 2 only: 1017 assert unichr(8364) == '€' 1018.. code:: python 1019 1020 # Python 3 only: 1021 assert chr(8364) == '€' 1022.. code:: python 1023 1024 # Python 2 and 3: 1025 from builtins import chr 1026 assert chr(8364) == '€' 1027intern() 1028~~~~~~~~ 1029 1030.. code:: python 1031 1032 # Python 2 only: 1033 intern('mystring') 1034.. code:: python 1035 1036 # Python 3 only: 1037 from sys import intern 1038 intern('mystring') 1039.. code:: python 1040 1041 # Python 2 and 3: alternative 1 1042 from past.builtins import intern 1043 intern('mystring') 1044.. code:: python 1045 1046 # Python 2 and 3: alternative 2 1047 from six.moves import intern 1048 intern('mystring') 1049.. code:: python 1050 1051 # Python 2 and 3: alternative 3 1052 from future.standard_library import install_aliases 1053 install_aliases() 1054 from sys import intern 1055 intern('mystring') 1056.. code:: python 1057 1058 # Python 2 and 3: alternative 2 1059 try: 1060 from sys import intern 1061 except ImportError: 1062 pass 1063 intern('mystring') 1064apply() 1065~~~~~~~ 1066 1067.. code:: python 1068 1069 args = ('a', 'b') 1070 kwargs = {'kwarg1': True} 1071.. code:: python 1072 1073 # Python 2 only: 1074 apply(f, args, kwargs) 1075.. code:: python 1076 1077 # Python 2 and 3: alternative 1 1078 f(*args, **kwargs) 1079.. code:: python 1080 1081 # Python 2 and 3: alternative 2 1082 from past.builtins import apply 1083 apply(f, args, kwargs) 1084chr() 1085~~~~~ 1086 1087.. code:: python 1088 1089 # Python 2 only: 1090 assert chr(64) == b'@' 1091 assert chr(200) == b'\xc8' 1092.. code:: python 1093 1094 # Python 3 only: option 1 1095 assert chr(64).encode('latin-1') == b'@' 1096 assert chr(0xc8).encode('latin-1') == b'\xc8' 1097.. code:: python 1098 1099 # Python 2 and 3: option 1 1100 from builtins import chr 1101 1102 assert chr(64).encode('latin-1') == b'@' 1103 assert chr(0xc8).encode('latin-1') == b'\xc8' 1104.. code:: python 1105 1106 # Python 3 only: option 2 1107 assert bytes([64]) == b'@' 1108 assert bytes([0xc8]) == b'\xc8' 1109.. code:: python 1110 1111 # Python 2 and 3: option 2 1112 from builtins import bytes 1113 1114 assert bytes([64]) == b'@' 1115 assert bytes([0xc8]) == b'\xc8' 1116cmp() 1117~~~~~ 1118 1119.. code:: python 1120 1121 # Python 2 only: 1122 assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0 1123.. code:: python 1124 1125 # Python 2 and 3: alternative 1 1126 from past.builtins import cmp 1127 assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0 1128.. code:: python 1129 1130 # Python 2 and 3: alternative 2 1131 cmp = lambda(x, y): (x > y) - (x < y) 1132 assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0 1133reload() 1134~~~~~~~~ 1135 1136.. code:: python 1137 1138 # Python 2 only: 1139 reload(mymodule) 1140.. code:: python 1141 1142 # Python 2 and 3 1143 from imp import reload 1144 reload(mymodule) 1145Standard library 1146---------------- 1147 1148dbm modules 1149~~~~~~~~~~~ 1150 1151.. code:: python 1152 1153 # Python 2 only 1154 import anydbm 1155 import whichdb 1156 import dbm 1157 import dumbdbm 1158 import gdbm 1159 1160 # Python 2 and 3: alternative 1 1161 from future import standard_library 1162 standard_library.install_aliases() 1163 1164 import dbm 1165 import dbm.ndbm 1166 import dbm.dumb 1167 import dbm.gnu 1168 1169 # Python 2 and 3: alternative 2 1170 from future.moves import dbm 1171 from future.moves.dbm import dumb 1172 from future.moves.dbm import ndbm 1173 from future.moves.dbm import gnu 1174 1175 # Python 2 and 3: alternative 3 1176 from six.moves import dbm_gnu 1177 # (others not supported) 1178commands / subprocess modules 1179~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1180 1181.. code:: python 1182 1183 # Python 2 only 1184 from commands import getoutput, getstatusoutput 1185 1186 # Python 2 and 3 1187 from future import standard_library 1188 standard_library.install_aliases() 1189 1190 from subprocess import getoutput, getstatusoutput 1191StringIO module 1192~~~~~~~~~~~~~~~ 1193 1194.. code:: python 1195 1196 # Python 2 only 1197 from StringIO import StringIO 1198 from cStringIO import StringIO 1199.. code:: python 1200 1201 # Python 2 and 3 1202 from io import BytesIO 1203 # and refactor StringIO() calls to BytesIO() if passing byte-strings 1204http module 1205~~~~~~~~~~~ 1206 1207.. code:: python 1208 1209 # Python 2 only: 1210 import httplib 1211 import Cookie 1212 import cookielib 1213 import BaseHTTPServer 1214 import SimpleHTTPServer 1215 import CGIHttpServer 1216 1217 # Python 2 and 3 (after ``pip install future``): 1218 import http.client 1219 import http.cookies 1220 import http.cookiejar 1221 import http.server 1222xmlrpc module 1223~~~~~~~~~~~~~ 1224 1225.. code:: python 1226 1227 # Python 2 only: 1228 import DocXMLRPCServer 1229 import SimpleXMLRPCServer 1230 1231 # Python 2 and 3 (after ``pip install future``): 1232 import xmlrpc.server 1233.. code:: python 1234 1235 # Python 2 only: 1236 import xmlrpclib 1237 1238 # Python 2 and 3 (after ``pip install future``): 1239 import xmlrpc.client 1240html escaping and entities 1241~~~~~~~~~~~~~~~~~~~~~~~~~~ 1242 1243.. code:: python 1244 1245 # Python 2 and 3: 1246 from cgi import escape 1247 1248 # Safer (Python 2 and 3, after ``pip install future``): 1249 from html import escape 1250 1251 # Python 2 only: 1252 from htmlentitydefs import codepoint2name, entitydefs, name2codepoint 1253 1254 # Python 2 and 3 (after ``pip install future``): 1255 from html.entities import codepoint2name, entitydefs, name2codepoint 1256html parsing 1257~~~~~~~~~~~~ 1258 1259.. code:: python 1260 1261 # Python 2 only: 1262 from HTMLParser import HTMLParser 1263 1264 # Python 2 and 3 (after ``pip install future``) 1265 from html.parser import HTMLParser 1266 1267 # Python 2 and 3 (alternative 2): 1268 from future.moves.html.parser import HTMLParser 1269urllib module 1270~~~~~~~~~~~~~ 1271 1272``urllib`` is the hardest module to use from Python 2/3 compatible code. 1273You might want to switch to Requests (http://python-requests.org) instead. 1274 1275.. code:: python 1276 1277 # Python 2 only: 1278 from urlparse import urlparse 1279 from urllib import urlencode 1280 from urllib2 import urlopen, Request, HTTPError 1281.. code:: python 1282 1283 # Python 3 only: 1284 from urllib.parse import urlparse, urlencode 1285 from urllib.request import urlopen, Request 1286 from urllib.error import HTTPError 1287.. code:: python 1288 1289 # Python 2 and 3: easiest option 1290 from future.standard_library import install_aliases 1291 install_aliases() 1292 1293 from urllib.parse import urlparse, urlencode 1294 from urllib.request import urlopen, Request 1295 from urllib.error import HTTPError 1296.. code:: python 1297 1298 # Python 2 and 3: alternative 2 1299 from future.standard_library import hooks 1300 1301 with hooks(): 1302 from urllib.parse import urlparse, urlencode 1303 from urllib.request import urlopen, Request 1304 from urllib.error import HTTPError 1305.. code:: python 1306 1307 # Python 2 and 3: alternative 3 1308 from future.moves.urllib.parse import urlparse, urlencode 1309 from future.moves.urllib.request import urlopen, Request 1310 from future.moves.urllib.error import HTTPError 1311 # or 1312 from six.moves.urllib.parse import urlparse, urlencode 1313 from six.moves.urllib.request import urlopen 1314 from six.moves.urllib.error import HTTPError 1315.. code:: python 1316 1317 # Python 2 and 3: alternative 4 1318 try: 1319 from urllib.parse import urlparse, urlencode 1320 from urllib.request import urlopen, Request 1321 from urllib.error import HTTPError 1322 except ImportError: 1323 from urlparse import urlparse 1324 from urllib import urlencode 1325 from urllib2 import urlopen, Request, HTTPError 1326Tkinter 1327~~~~~~~ 1328 1329.. code:: python 1330 1331 # Python 2 only: 1332 import Tkinter 1333 import Dialog 1334 import FileDialog 1335 import ScrolledText 1336 import SimpleDialog 1337 import Tix 1338 import Tkconstants 1339 import Tkdnd 1340 import tkColorChooser 1341 import tkCommonDialog 1342 import tkFileDialog 1343 import tkFont 1344 import tkMessageBox 1345 import tkSimpleDialog 1346 import ttk 1347 1348 # Python 2 and 3 (after ``pip install future``): 1349 import tkinter 1350 import tkinter.dialog 1351 import tkinter.filedialog 1352 import tkinter.scrolledtext 1353 import tkinter.simpledialog 1354 import tkinter.tix 1355 import tkinter.constants 1356 import tkinter.dnd 1357 import tkinter.colorchooser 1358 import tkinter.commondialog 1359 import tkinter.filedialog 1360 import tkinter.font 1361 import tkinter.messagebox 1362 import tkinter.simpledialog 1363 import tkinter.ttk 1364socketserver 1365~~~~~~~~~~~~ 1366 1367.. code:: python 1368 1369 # Python 2 only: 1370 import SocketServer 1371 1372 # Python 2 and 3 (after ``pip install future``): 1373 import socketserver 1374copy\_reg, copyreg 1375~~~~~~~~~~~~~~~~~~ 1376 1377.. code:: python 1378 1379 # Python 2 only: 1380 import copy_reg 1381 1382 # Python 2 and 3 (after ``pip install future``): 1383 import copyreg 1384configparser 1385~~~~~~~~~~~~ 1386 1387.. code:: python 1388 1389 # Python 2 only: 1390 from ConfigParser import ConfigParser 1391 1392 # Python 2 and 3 (after ``pip install configparser``): 1393 from configparser import ConfigParser 1394queue 1395~~~~~ 1396 1397.. code:: python 1398 1399 # Python 2 only: 1400 from Queue import Queue, heapq, deque 1401 1402 # Python 2 and 3 (after ``pip install future``): 1403 from queue import Queue, heapq, deque 1404repr, reprlib 1405~~~~~~~~~~~~~ 1406 1407.. code:: python 1408 1409 # Python 2 only: 1410 from repr import aRepr, repr 1411 1412 # Python 2 and 3 (after ``pip install future``): 1413 from reprlib import aRepr, repr 1414UserDict, UserList, UserString 1415~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1416 1417.. code:: python 1418 1419 # Python 2 only: 1420 from UserDict import UserDict 1421 from UserList import UserList 1422 from UserString import UserString 1423 1424 # Python 3 only: 1425 from collections import UserDict, UserList, UserString 1426 1427 # Python 2 and 3: alternative 1 1428 from future.moves.collections import UserDict, UserList, UserString 1429 1430 # Python 2 and 3: alternative 2 1431 from six.moves import UserDict, UserList, UserString 1432 1433 # Python 2 and 3: alternative 3 1434 from future.standard_library import install_aliases 1435 install_aliases() 1436 from collections import UserDict, UserList, UserString 1437itertools: filterfalse, zip\_longest 1438~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1439 1440.. code:: python 1441 1442 # Python 2 only: 1443 from itertools import ifilterfalse, izip_longest 1444 1445 # Python 3 only: 1446 from itertools import filterfalse, zip_longest 1447 1448 # Python 2 and 3: alternative 1 1449 from future.moves.itertools import filterfalse, zip_longest 1450 1451 # Python 2 and 3: alternative 2 1452 from six.moves import filterfalse, zip_longest 1453 1454 # Python 2 and 3: alternative 3 1455 from future.standard_library import install_aliases 1456 install_aliases() 1457 from itertools import filterfalse, zip_longest 1458