mirror of
https://github.com/rasbt/python_reference.git
synced 2024-11-27 22:11:13 +00:00
2 new sections
This commit is contained in:
parent
cb5853e6da
commit
34175c785a
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"metadata": {
|
||||
"name": "",
|
||||
"signature": "sha256:3b7a6d43400c23d25d965b726e6fba3db0b9b0d2d0bbad73c96b8857f8eaa7ee"
|
||||
"signature": "sha256:0e1c6e74b301e23ea4146d660afb3f07765686c6c7fa4752f3a4495da7949787"
|
||||
},
|
||||
"nbformat": 3,
|
||||
"nbformat_minor": 0,
|
||||
|
@ -13,7 +13,7 @@
|
|||
"metadata": {},
|
||||
"source": [
|
||||
"Sebastian Raschka \n",
|
||||
"last updated: 05/02/2014 ([Changelog](#changelog))\n",
|
||||
"last updated: 05/03/2014 ([Changelog](#changelog))\n",
|
||||
"\n",
|
||||
"[Link to this IPython Notebook on GitHub](https://github.com/rasbt/python_reference/blob/master/not_so_obvious_python_stuff.ipynb)\n",
|
||||
"\n",
|
||||
|
@ -83,7 +83,9 @@
|
|||
"- [Assigning types to variables as values](#variable_types)\n",
|
||||
"- [Only the first clause of generators is evaluated immediately](#generator_rhs)\n",
|
||||
"- [Keyword argument unpacking syntax - `*args` and `**kwargs`](#splat_op)\n",
|
||||
"- [Metaclasses - What creates a new instance of a class?](#new_instance)"
|
||||
"- [Metaclasses - What creates a new instance of a class?](#new_instance)\n",
|
||||
"- [Else-clauses: \"conditional else\" and \"completion else\"](#else_clauses)\n",
|
||||
"- [Interning of compile-time constants vs. run-time expressions](#string_interning)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -3278,6 +3280,13 @@
|
|||
"## Metaclasses - What creates a new instance of a class?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[[back to top](#sections)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
@ -3361,6 +3370,545 @@
|
|||
],
|
||||
"prompt_number": 54
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"for i in range(5):\n",
|
||||
" if i == 1:\n",
|
||||
" print('in for')\n",
|
||||
"else:\n",
|
||||
" print('in else')\n",
|
||||
"print('after for-loop')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"in for\n",
|
||||
"in else\n",
|
||||
"after for-loop\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 5
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"for i in range(5):\n",
|
||||
" if i == 1:\n",
|
||||
" break\n",
|
||||
"else:\n",
|
||||
" print('in else')\n",
|
||||
"print('after for-loop')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"after for-loop\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 6
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<a name=\"else_clauses\"></a>\n",
|
||||
"<br>\n",
|
||||
"<br>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Else-clauses: \"conditional else\" and \"completion else\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[[back to top](#sections)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"I would claim that the conditional \"else\" is every programmer's daily bread and butter. However, there is a second flavor of \"else\"-clauses in Python, which I will call \"completion else\" (for reason that will become clear later). \n",
|
||||
"But first, let us take a look at our \"traditional\" conditional else that we all are familiar with. \n",
|
||||
"### Conditional else:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"# conditional else\n",
|
||||
"\n",
|
||||
"a_list = [1,2]\n",
|
||||
"if a_list[0] == 1:\n",
|
||||
" print('Hello, World!')\n",
|
||||
"else:\n",
|
||||
" print('Bye, World!')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"Hello, World!\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 3
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"# conditional else\n",
|
||||
"\n",
|
||||
"a_list = [1,2]\n",
|
||||
"if a_list[0] == 2:\n",
|
||||
" print('Hello, World!')\n",
|
||||
"else:\n",
|
||||
" print('Bye, World!')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"Bye, World!\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 4
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Why am I showing those simple examples? I think they are good to highlight some of the key points: It is **either** the code under the `if` clause that is executed, **or** the code under the `else` block, but not both. \n",
|
||||
"If the condition of the `if` clause evaluates to `True`, the `if`-block is exectured, and if it evaluated to `False`, it is the `else` block. \n",
|
||||
"\n",
|
||||
"### Completion else\n",
|
||||
"**In contrast** to the **either...or*** situation that we know from the conditional `else`, the completion `else` is executed if a code block finished. \n",
|
||||
"To show you an example, let us use `else` for error-handling:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Completion else (try-except)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"try:\n",
|
||||
" print('first element:', a_list[0])\n",
|
||||
"except IndexError:\n",
|
||||
" print('raised IndexError')\n",
|
||||
"else:\n",
|
||||
" print('no error in try-block')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"first element: 1\n",
|
||||
"no error in try-block\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 5
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"try:\n",
|
||||
" print('third element:', a_list[2])\n",
|
||||
"except IndexError:\n",
|
||||
" print('raised IndexError')\n",
|
||||
"else:\n",
|
||||
" print('no error in try-block')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"raised IndexError\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 6
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<br>\n",
|
||||
"In the code above, we can see that the code under the **`else`-clause is only executed if the `try-block` was executed without encountering an error, i.e., if the `try`-block is \"complete\".** \n",
|
||||
"The same rule applies to the \"completion\" `else` in while- and for-loops, which you can confirm in the following samples below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Completion else (while-loop)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"i = 0\n",
|
||||
"while i < 2:\n",
|
||||
" print(i)\n",
|
||||
" i += 1\n",
|
||||
"else:\n",
|
||||
" print('in else')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"0\n",
|
||||
"1\n",
|
||||
"in else\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 7
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"i = 0\n",
|
||||
"while i < 2:\n",
|
||||
" print(i)\n",
|
||||
" i += 1\n",
|
||||
" break\n",
|
||||
"else:\n",
|
||||
" print('completed while-loop')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 8
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Completion else (for-loop)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"for i in range(2):\n",
|
||||
" print(i)\n",
|
||||
"else:\n",
|
||||
" print('completed for-loop')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"0\n",
|
||||
"1\n",
|
||||
"completed for-loop\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 9
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"for i in range(2):\n",
|
||||
" print(i)\n",
|
||||
" break\n",
|
||||
"else:\n",
|
||||
" print('completed for-loop')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 10
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<a name=\"string_interning\"></a>\n",
|
||||
"<br>\n",
|
||||
"<br>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Interning of compile-time constants vs. run-time expressions"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[[back to top](#sections)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This might not be particularly useful, but it is nonetheless interesting: Python's interpreter is interning compile-time constants but not run-time expressions (note that this is implementation-specific).\n",
|
||||
"\n",
|
||||
"(Original source: [Stackoverflow](http://stackoverflow.com/questions/15541404/python-string-interning))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let us have a look at the simple example below. Here we are creating 3 variables and assign the value \"Hello\" to them in different ways before we test them for identity."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"hello1 = 'Hello'\n",
|
||||
"\n",
|
||||
"hello2 = 'Hell' + 'o'\n",
|
||||
"\n",
|
||||
"hello3 = 'Hell'\n",
|
||||
"hello3 = hello3 + 'o'\n",
|
||||
"\n",
|
||||
"print('hello1 is hello2:', hello1 is hello2)\n",
|
||||
"print('hello1 is hello3:', hello1 is hello3)"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"hello1 is hello2: True\n",
|
||||
"hello1 is hello3: False\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 34
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now, how does it come that the first expression evaluates to true, but the second does not? To answer this question, we need to take a closer look at the underlying byte codes:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"import dis\n",
|
||||
"def hello1_func():\n",
|
||||
" s = 'Hello'\n",
|
||||
" return s\n",
|
||||
"dis.dis(hello1_func)"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
" 3 0 LOAD_CONST 1 ('Hello')\n",
|
||||
" 3 STORE_FAST 0 (s)\n",
|
||||
"\n",
|
||||
" 4 6 LOAD_FAST 0 (s)\n",
|
||||
" 9 RETURN_VALUE\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 38
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"def hello2_func():\n",
|
||||
" s = 'Hell' + 'o'\n",
|
||||
" return s\n",
|
||||
"dis.dis(hello2_func)"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
" 2 0 LOAD_CONST 3 ('Hello')\n",
|
||||
" 3 STORE_FAST 0 (s)\n",
|
||||
"\n",
|
||||
" 3 6 LOAD_FAST 0 (s)\n",
|
||||
" 9 RETURN_VALUE\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 39
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"def hello3_func():\n",
|
||||
" s = 'Hell'\n",
|
||||
" s = s + 'o'\n",
|
||||
" return s\n",
|
||||
"dis.dis(hello3_func)"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
" 2 0 LOAD_CONST 1 ('Hell')\n",
|
||||
" 3 STORE_FAST 0 (s)\n",
|
||||
"\n",
|
||||
" 3 6 LOAD_FAST 0 (s)\n",
|
||||
" 9 LOAD_CONST 2 ('o')\n",
|
||||
" 12 BINARY_ADD\n",
|
||||
" 13 STORE_FAST 0 (s)\n",
|
||||
"\n",
|
||||
" 4 16 LOAD_FAST 0 (s)\n",
|
||||
" 19 RETURN_VALUE\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 40
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<br>\n",
|
||||
"It looks like that `'Hello'` and `'Hell'` + `'o'` are both evaluated and stored as `'Hello'` at compile-time, whereas the third version \n",
|
||||
"`s = 'Hell'` \n",
|
||||
"`s = s + 'o'` seems to be not interned. Let us quickly confirm the behavior with the following code:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"print(hello1_func() is hello2_func())\n",
|
||||
"print(hello1_func() is hello3_func())"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"True\n",
|
||||
"False\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 42
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Finally, to show that this hypothesis is the answer to this rather unexpected observation, let us `intern` the value manually:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"print(hello1_func() is sys.intern(hello3_func()))"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"True\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 45
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
@ -3390,8 +3938,12 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### 05/03/2014\n",
|
||||
"- new section: else clauses: conditional vs. completion\n",
|
||||
"- new section: Interning of compile-time constants vs. run-time expressions\n",
|
||||
"\n",
|
||||
"#### 05/02/2014\n",
|
||||
"- new section in Python 3.x and Python 2.x key differences: for-loop leak<\n",
|
||||
"- new section in Python 3.x and Python 2.x key differences: for-loop leak\n",
|
||||
"- new section: Metaclasses - What creates a new instance of a class? \n",
|
||||
"\n",
|
||||
"#### 05/01/2014\n",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"metadata": {
|
||||
"name": "",
|
||||
"signature": "sha256:3b7a6d43400c23d25d965b726e6fba3db0b9b0d2d0bbad73c96b8857f8eaa7ee"
|
||||
"signature": "sha256:0e1c6e74b301e23ea4146d660afb3f07765686c6c7fa4752f3a4495da7949787"
|
||||
},
|
||||
"nbformat": 3,
|
||||
"nbformat_minor": 0,
|
||||
|
@ -13,7 +13,7 @@
|
|||
"metadata": {},
|
||||
"source": [
|
||||
"Sebastian Raschka \n",
|
||||
"last updated: 05/02/2014 ([Changelog](#changelog))\n",
|
||||
"last updated: 05/03/2014 ([Changelog](#changelog))\n",
|
||||
"\n",
|
||||
"[Link to this IPython Notebook on GitHub](https://github.com/rasbt/python_reference/blob/master/not_so_obvious_python_stuff.ipynb)\n",
|
||||
"\n",
|
||||
|
@ -83,7 +83,9 @@
|
|||
"- [Assigning types to variables as values](#variable_types)\n",
|
||||
"- [Only the first clause of generators is evaluated immediately](#generator_rhs)\n",
|
||||
"- [Keyword argument unpacking syntax - `*args` and `**kwargs`](#splat_op)\n",
|
||||
"- [Metaclasses - What creates a new instance of a class?](#new_instance)"
|
||||
"- [Metaclasses - What creates a new instance of a class?](#new_instance)\n",
|
||||
"- [Else-clauses: \"conditional else\" and \"completion else\"](#else_clauses)\n",
|
||||
"- [Interning of compile-time constants vs. run-time expressions](#string_interning)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -3278,6 +3280,13 @@
|
|||
"## Metaclasses - What creates a new instance of a class?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[[back to top](#sections)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
@ -3361,6 +3370,545 @@
|
|||
],
|
||||
"prompt_number": 54
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"for i in range(5):\n",
|
||||
" if i == 1:\n",
|
||||
" print('in for')\n",
|
||||
"else:\n",
|
||||
" print('in else')\n",
|
||||
"print('after for-loop')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"in for\n",
|
||||
"in else\n",
|
||||
"after for-loop\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 5
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"for i in range(5):\n",
|
||||
" if i == 1:\n",
|
||||
" break\n",
|
||||
"else:\n",
|
||||
" print('in else')\n",
|
||||
"print('after for-loop')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"after for-loop\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 6
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<a name=\"else_clauses\"></a>\n",
|
||||
"<br>\n",
|
||||
"<br>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Else-clauses: \"conditional else\" and \"completion else\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[[back to top](#sections)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"I would claim that the conditional \"else\" is every programmer's daily bread and butter. However, there is a second flavor of \"else\"-clauses in Python, which I will call \"completion else\" (for reason that will become clear later). \n",
|
||||
"But first, let us take a look at our \"traditional\" conditional else that we all are familiar with. \n",
|
||||
"### Conditional else:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"# conditional else\n",
|
||||
"\n",
|
||||
"a_list = [1,2]\n",
|
||||
"if a_list[0] == 1:\n",
|
||||
" print('Hello, World!')\n",
|
||||
"else:\n",
|
||||
" print('Bye, World!')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"Hello, World!\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 3
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"# conditional else\n",
|
||||
"\n",
|
||||
"a_list = [1,2]\n",
|
||||
"if a_list[0] == 2:\n",
|
||||
" print('Hello, World!')\n",
|
||||
"else:\n",
|
||||
" print('Bye, World!')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"Bye, World!\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 4
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Why am I showing those simple examples? I think they are good to highlight some of the key points: It is **either** the code under the `if` clause that is executed, **or** the code under the `else` block, but not both. \n",
|
||||
"If the condition of the `if` clause evaluates to `True`, the `if`-block is exectured, and if it evaluated to `False`, it is the `else` block. \n",
|
||||
"\n",
|
||||
"### Completion else\n",
|
||||
"**In contrast** to the **either...or*** situation that we know from the conditional `else`, the completion `else` is executed if a code block finished. \n",
|
||||
"To show you an example, let us use `else` for error-handling:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Completion else (try-except)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"try:\n",
|
||||
" print('first element:', a_list[0])\n",
|
||||
"except IndexError:\n",
|
||||
" print('raised IndexError')\n",
|
||||
"else:\n",
|
||||
" print('no error in try-block')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"first element: 1\n",
|
||||
"no error in try-block\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 5
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"try:\n",
|
||||
" print('third element:', a_list[2])\n",
|
||||
"except IndexError:\n",
|
||||
" print('raised IndexError')\n",
|
||||
"else:\n",
|
||||
" print('no error in try-block')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"raised IndexError\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 6
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<br>\n",
|
||||
"In the code above, we can see that the code under the **`else`-clause is only executed if the `try-block` was executed without encountering an error, i.e., if the `try`-block is \"complete\".** \n",
|
||||
"The same rule applies to the \"completion\" `else` in while- and for-loops, which you can confirm in the following samples below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Completion else (while-loop)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"i = 0\n",
|
||||
"while i < 2:\n",
|
||||
" print(i)\n",
|
||||
" i += 1\n",
|
||||
"else:\n",
|
||||
" print('in else')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"0\n",
|
||||
"1\n",
|
||||
"in else\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 7
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"i = 0\n",
|
||||
"while i < 2:\n",
|
||||
" print(i)\n",
|
||||
" i += 1\n",
|
||||
" break\n",
|
||||
"else:\n",
|
||||
" print('completed while-loop')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 8
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Completion else (for-loop)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"for i in range(2):\n",
|
||||
" print(i)\n",
|
||||
"else:\n",
|
||||
" print('completed for-loop')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"0\n",
|
||||
"1\n",
|
||||
"completed for-loop\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 9
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"for i in range(2):\n",
|
||||
" print(i)\n",
|
||||
" break\n",
|
||||
"else:\n",
|
||||
" print('completed for-loop')"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 10
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<a name=\"string_interning\"></a>\n",
|
||||
"<br>\n",
|
||||
"<br>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Interning of compile-time constants vs. run-time expressions"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[[back to top](#sections)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This might not be particularly useful, but it is nonetheless interesting: Python's interpreter is interning compile-time constants but not run-time expressions (note that this is implementation-specific).\n",
|
||||
"\n",
|
||||
"(Original source: [Stackoverflow](http://stackoverflow.com/questions/15541404/python-string-interning))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let us have a look at the simple example below. Here we are creating 3 variables and assign the value \"Hello\" to them in different ways before we test them for identity."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"hello1 = 'Hello'\n",
|
||||
"\n",
|
||||
"hello2 = 'Hell' + 'o'\n",
|
||||
"\n",
|
||||
"hello3 = 'Hell'\n",
|
||||
"hello3 = hello3 + 'o'\n",
|
||||
"\n",
|
||||
"print('hello1 is hello2:', hello1 is hello2)\n",
|
||||
"print('hello1 is hello3:', hello1 is hello3)"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"hello1 is hello2: True\n",
|
||||
"hello1 is hello3: False\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 34
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now, how does it come that the first expression evaluates to true, but the second does not? To answer this question, we need to take a closer look at the underlying byte codes:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"import dis\n",
|
||||
"def hello1_func():\n",
|
||||
" s = 'Hello'\n",
|
||||
" return s\n",
|
||||
"dis.dis(hello1_func)"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
" 3 0 LOAD_CONST 1 ('Hello')\n",
|
||||
" 3 STORE_FAST 0 (s)\n",
|
||||
"\n",
|
||||
" 4 6 LOAD_FAST 0 (s)\n",
|
||||
" 9 RETURN_VALUE\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 38
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"def hello2_func():\n",
|
||||
" s = 'Hell' + 'o'\n",
|
||||
" return s\n",
|
||||
"dis.dis(hello2_func)"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
" 2 0 LOAD_CONST 3 ('Hello')\n",
|
||||
" 3 STORE_FAST 0 (s)\n",
|
||||
"\n",
|
||||
" 3 6 LOAD_FAST 0 (s)\n",
|
||||
" 9 RETURN_VALUE\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 39
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"def hello3_func():\n",
|
||||
" s = 'Hell'\n",
|
||||
" s = s + 'o'\n",
|
||||
" return s\n",
|
||||
"dis.dis(hello3_func)"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
" 2 0 LOAD_CONST 1 ('Hell')\n",
|
||||
" 3 STORE_FAST 0 (s)\n",
|
||||
"\n",
|
||||
" 3 6 LOAD_FAST 0 (s)\n",
|
||||
" 9 LOAD_CONST 2 ('o')\n",
|
||||
" 12 BINARY_ADD\n",
|
||||
" 13 STORE_FAST 0 (s)\n",
|
||||
"\n",
|
||||
" 4 16 LOAD_FAST 0 (s)\n",
|
||||
" 19 RETURN_VALUE\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 40
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<br>\n",
|
||||
"It looks like that `'Hello'` and `'Hell'` + `'o'` are both evaluated and stored as `'Hello'` at compile-time, whereas the third version \n",
|
||||
"`s = 'Hell'` \n",
|
||||
"`s = s + 'o'` seems to be not interned. Let us quickly confirm the behavior with the following code:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"print(hello1_func() is hello2_func())\n",
|
||||
"print(hello1_func() is hello3_func())"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"True\n",
|
||||
"False\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 42
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Finally, to show that this hypothesis is the answer to this rather unexpected observation, let us `intern` the value manually:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"print(hello1_func() is sys.intern(hello3_func()))"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"stream": "stdout",
|
||||
"text": [
|
||||
"True\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"prompt_number": 45
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
@ -3390,8 +3938,12 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### 05/03/2014\n",
|
||||
"- new section: else clauses: conditional vs. completion\n",
|
||||
"- new section: Interning of compile-time constants vs. run-time expressions\n",
|
||||
"\n",
|
||||
"#### 05/02/2014\n",
|
||||
"- new section in Python 3.x and Python 2.x key differences: for-loop leak<\n",
|
||||
"- new section in Python 3.x and Python 2.x key differences: for-loop leak\n",
|
||||
"- new section: Metaclasses - What creates a new instance of a class? \n",
|
||||
"\n",
|
||||
"#### 05/01/2014\n",
|
||||
|
|
Loading…
Reference in New Issue
Block a user