|
1 | 1 | { |
2 | 2 | "metadata": { |
3 | 3 | "name": "", |
4 | | - "signature": "sha256:06e485535e22c756262f09d4477108b57d0fa1029f9831ee77a177267f5afc7f" |
| 4 | + "signature": "sha256:1b145c7412627e0fa1c08e3b663174712154077c8d8b7740f66d3021a06216a4" |
5 | 5 | }, |
6 | 6 | "nbformat": 3, |
7 | 7 | "nbformat_minor": 0, |
|
47 | 47 | "- [Be aware of the consuming generator](#consuming_generator)\n", |
48 | 48 | "- [`bool` is a subclass of `int`](#bool_int)\n", |
49 | 49 | "- [About lambda and closures-in-a-loop pitfall](#lambda_closure)\n", |
50 | | - "- [Python's LEGB scope resolution and the keywords `global` and `nonlocal`](#python_legb)" |
| 50 | + "- [Python's LEGB scope resolution and the keywords `global` and `nonlocal`](#python_legb)\n", |
| 51 | + "- [When immutable Tuples aren't so immutable](#immutable_tuple)" |
51 | 52 | ] |
52 | 53 | }, |
53 | 54 | { |
|
818 | 819 | } |
819 | 820 | ], |
820 | 821 | "prompt_number": 35 |
| 822 | + }, |
| 823 | + { |
| 824 | + "cell_type": "markdown", |
| 825 | + "metadata": {}, |
| 826 | + "source": [ |
| 827 | + "<br>\n", |
| 828 | + "<br>\n", |
| 829 | + "<a name='immutable_tuple'></a>\n", |
| 830 | + "## When immutable Tuples aren't so immutable" |
| 831 | + ] |
| 832 | + }, |
| 833 | + { |
| 834 | + "cell_type": "markdown", |
| 835 | + "metadata": {}, |
| 836 | + "source": [ |
| 837 | + "As we all know, tuples are immutable objects in Python, right!?" |
| 838 | + ] |
| 839 | + }, |
| 840 | + { |
| 841 | + "cell_type": "code", |
| 842 | + "collapsed": false, |
| 843 | + "input": [ |
| 844 | + "tup = (1,)\n", |
| 845 | + "tup[0] += 1" |
| 846 | + ], |
| 847 | + "language": "python", |
| 848 | + "metadata": {}, |
| 849 | + "outputs": [ |
| 850 | + { |
| 851 | + "ename": "TypeError", |
| 852 | + "evalue": "'tuple' object does not support item assignment", |
| 853 | + "output_type": "pyerr", |
| 854 | + "traceback": [ |
| 855 | + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", |
| 856 | + "\u001b[0;32m<ipython-input-41-c3bec6c3fe6f>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mtup\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mtup\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", |
| 857 | + "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" |
| 858 | + ] |
| 859 | + } |
| 860 | + ], |
| 861 | + "prompt_number": 41 |
| 862 | + }, |
| 863 | + { |
| 864 | + "cell_type": "markdown", |
| 865 | + "metadata": {}, |
| 866 | + "source": [ |
| 867 | + "#### But what if we put a mutable object into the immutable tuple? Well, modification works, but we **also** get a type error, funny, isn't it?" |
| 868 | + ] |
| 869 | + }, |
| 870 | + { |
| 871 | + "cell_type": "code", |
| 872 | + "collapsed": false, |
| 873 | + "input": [ |
| 874 | + "tup = ([],)\n", |
| 875 | + "print('tup before: ', tup)\n", |
| 876 | + "tup[0] += [1]" |
| 877 | + ], |
| 878 | + "language": "python", |
| 879 | + "metadata": {}, |
| 880 | + "outputs": [ |
| 881 | + { |
| 882 | + "output_type": "stream", |
| 883 | + "stream": "stdout", |
| 884 | + "text": [ |
| 885 | + "tup before: ([],)\n" |
| 886 | + ] |
| 887 | + }, |
| 888 | + { |
| 889 | + "ename": "TypeError", |
| 890 | + "evalue": "'tuple' object does not support item assignment", |
| 891 | + "output_type": "pyerr", |
| 892 | + "traceback": [ |
| 893 | + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", |
| 894 | + "\u001b[0;32m<ipython-input-42-aebe9a31dbeb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mtup\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'tup before: '\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtup\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mtup\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", |
| 895 | + "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" |
| 896 | + ] |
| 897 | + } |
| 898 | + ], |
| 899 | + "prompt_number": 42 |
| 900 | + }, |
| 901 | + { |
| 902 | + "cell_type": "code", |
| 903 | + "collapsed": false, |
| 904 | + "input": [ |
| 905 | + "print('tup after: ', tup)" |
| 906 | + ], |
| 907 | + "language": "python", |
| 908 | + "metadata": {}, |
| 909 | + "outputs": [ |
| 910 | + { |
| 911 | + "output_type": "stream", |
| 912 | + "stream": "stdout", |
| 913 | + "text": [ |
| 914 | + "tup after: ([1],)\n" |
| 915 | + ] |
| 916 | + } |
| 917 | + ], |
| 918 | + "prompt_number": 43 |
| 919 | + }, |
| 920 | + { |
| 921 | + "cell_type": "markdown", |
| 922 | + "metadata": {}, |
| 923 | + "source": [ |
| 924 | + "<br>\n", |
| 925 | + "<br>\n", |
| 926 | + "However, there **IS** a way (where there should be none!) to modify our immutable tuple without raising the `TypeError`, the solution is the `.extend()`:" |
| 927 | + ] |
| 928 | + }, |
| 929 | + { |
| 930 | + "cell_type": "code", |
| 931 | + "collapsed": false, |
| 932 | + "input": [ |
| 933 | + "tup = ([],)\n", |
| 934 | + "print('tup before: ', tup)\n", |
| 935 | + "tup[0].extend([1])\n", |
| 936 | + "print('tup after: ', tup)" |
| 937 | + ], |
| 938 | + "language": "python", |
| 939 | + "metadata": {}, |
| 940 | + "outputs": [ |
| 941 | + { |
| 942 | + "output_type": "stream", |
| 943 | + "stream": "stdout", |
| 944 | + "text": [ |
| 945 | + "tup before: ([],)\n", |
| 946 | + "tup after: ([1],)\n" |
| 947 | + ] |
| 948 | + } |
| 949 | + ], |
| 950 | + "prompt_number": 44 |
| 951 | + }, |
| 952 | + { |
| 953 | + "cell_type": "markdown", |
| 954 | + "metadata": {}, |
| 955 | + "source": [ |
| 956 | + "### Explanation\n", |
| 957 | + "\n", |
| 958 | + "**A. Jesse Jiryu Davis** has a nice explanation for this phenomenon (Original source: [http://emptysqua.re/blog/python-increment-is-weird-part-ii/](http://emptysqua.re/blog/python-increment-is-weird-part-ii/))\n", |
| 959 | + "\n", |
| 960 | + "If we try to extend the list via `+=` *\"then the statement executes STORE_SUBSCR, which calls the C function PyObject_SetItem, which checks if the object supports item assignment. In our case the object is a tuple, so PyObject_SetItem throws the TypeError. Mystery solved.\"*" |
| 961 | + ] |
821 | 962 | } |
822 | 963 | ], |
823 | 964 | "metadata": {} |
|
0 commit comments