diff --git a/.ipynb_checkpoints/not_so_obvious_python_stuff-checkpoint.ipynb b/.ipynb_checkpoints/not_so_obvious_python_stuff-checkpoint.ipynb
index 9b60f15..5497f91 100644
--- a/.ipynb_checkpoints/not_so_obvious_python_stuff-checkpoint.ipynb
+++ b/.ipynb_checkpoints/not_so_obvious_python_stuff-checkpoint.ipynb
@@ -1,7 +1,7 @@
{
"metadata": {
"name": "",
- "signature": "sha256:ef925e4eaf58c6daf50a495a77d38aa0b02a365dfc972bb5c0174332360b5adb"
+ "signature": "sha256:35f23d6f2bbaa131a262533ed080684ed53fc0260430780f248c09af8c645759"
},
"nbformat": 3,
"nbformat_minor": 0,
@@ -69,7 +69,8 @@
"- [List slicing using indexes that are \"out of range](#out_of_range_slicing)\n",
"- [Reusing global variable names and UnboundLocalErrors](#unboundlocalerror)\n",
"- [Creating copies of mutable objects](#copy_mutable)\n",
- "- [Key differences between Python 2 and 3](#python_differences)"
+ "- [Key differences between Python 2 and 3](#python_differences)\n",
+ "- [Function annotations - What are those `->`'s in my Python code?](#function_annotation)"
]
},
{
@@ -1807,6 +1808,7 @@
"source": [
"
\n",
"
\n",
+ "\n",
"## Key differences between Python 2 and 3\n",
"\n",
"There are some good articles already that are summarizing the differences between Python 2 and 3, e.g., \n",
@@ -2043,6 +2045,15 @@
"metadata": {},
"outputs": []
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Handling exceptions\n",
+ "\n",
+ "Also the handling of excecptions has slightly changed in Python 3. Now, we have to use the `as` keyword!"
+ ]
+ },
{
"cell_type": "code",
"collapsed": false,
@@ -2061,11 +2072,266 @@
"... except NameError as err:\n",
"... print(err, '--> our error msg')\n",
"... \n",
- "name 'blabla' is not defined --> our error msg\n"
+ "name 'blabla' is not defined --> our error msg"
],
"language": "python",
"metadata": {},
"outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### The `next()` function and `.next()` method\n",
+ "\n",
+ "Where you can use both function and method in Python 2.7.5, the `next()` function is all that remain in Python 3!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "# Python 2\n",
+ ">>> my_generator = (letter for letter in 'abcdefg')\n",
+ ">>> my_generator.next()\n",
+ "'a'\n",
+ ">>> next(my_generator)\n",
+ "'b'\n",
+ "\n",
+ "# Python 3\n",
+ ">>> my_generator = (letter for letter in 'abcdefg')\n",
+ ">>> next(my_generator)\n",
+ "'a'\n",
+ ">>> my_generator.next()\n",
+ "Traceback (most recent call last):\n",
+ " File \"\", line 1, in \n",
+ "AttributeError: 'generator' object has no attribute 'next'"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
\n",
+ "\n",
+ "## Function annotations - What are those `->`'s in my Python code?\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Have you ever seen any Python code that used colons inside the parantheses of a function definition?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "def foo1(x: 'insert x here', y: 'insert x^2 here'):\n",
+ " print('Hello, World')\n",
+ " return"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [],
+ "prompt_number": 8
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "And what about the fancy arrow here?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "def foo2(x, y) -> 'Hi!':\n",
+ " print('Hello, World')\n",
+ " return"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [],
+ "prompt_number": 10
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Q: Is this valid Python syntax? \n",
+ "A: Yes!\n",
+ " \n",
+ " \n",
+ "Q: So, what happens if I *just call* the function? \n",
+ "A: Nothing!\n",
+ " \n",
+ "Here is the proof!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "foo1(1,2)"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [
+ {
+ "output_type": "stream",
+ "stream": "stdout",
+ "text": [
+ "Hello, World\n"
+ ]
+ }
+ ],
+ "prompt_number": 9
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "foo2(1,2) "
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [
+ {
+ "output_type": "stream",
+ "stream": "stdout",
+ "text": [
+ "Hello, World\n"
+ ]
+ }
+ ],
+ "prompt_number": 11
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**So, those are function annotations ... ** \n",
+ "- the colon for the function parameters \n",
+ "- the arrow for the return value \n",
+ "\n",
+ "You probably will never make use of them (or at least very rarely). Usually, we write good function documentations below the function as a docstring - or at least this is how I would do it (okay this case is a little bit extreme, I have to admit):"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "def is_palindrome(a):\n",
+ " \"\"\"\n",
+ " Case-and punctuation insensitive check if a string is a palindrom.\n",
+ " \n",
+ " Keyword arguments:\n",
+ " a (str): The string to be checked if it is a palindrome.\n",
+ " \n",
+ " Returns `True` if input string is a palindrome, else False.\n",
+ " \n",
+ " \"\"\"\n",
+ " stripped_str = [l for l in my_str.lower() if l.isalpha()]\n",
+ " return stripped_str == stripped_str[::-1]\n",
+ " "
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "However, function annotations can be useful to indicate that work is still in progress in some cases. But they are optional and I see them very very rarely.\n",
+ "\n",
+ "As it is stated in [PEP3107](http://legacy.python.org/dev/peps/pep-3107/#fundamentals-of-function-annotations):\n",
+ "\n",
+ "1. Function annotations, both for parameters and return values, are completely optional.\n",
+ "\n",
+ "2. Function annotations are nothing more than a way of associating arbitrary Python expressions with various parts of a function at compile-time.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The nice thing about function annotations is their `__annotations__` attribute, which is dictionary of all the parameters and/or the `return` value you annotated."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "foo1.__annotations__"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [
+ {
+ "metadata": {},
+ "output_type": "pyout",
+ "prompt_number": 17,
+ "text": [
+ "{'y': 'insert x^2 here', 'x': 'insert x here'}"
+ ]
+ }
+ ],
+ "prompt_number": 17
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "foo2.__annotations__"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [
+ {
+ "metadata": {},
+ "output_type": "pyout",
+ "prompt_number": 18,
+ "text": [
+ "{'return': 'Hi!'}"
+ ]
+ }
+ ],
+ "prompt_number": 18
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**When are they useful?**"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Function annotations can be useful for a couple of things \n",
+ "- Documentation in general\n",
+ "- pre-condition testing\n",
+ "- [type checking](http://legacy.python.org/dev/peps/pep-0362/#annotation-checker)\n",
+ " \n",
+ "..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [],
+ "language": "python",
+ "metadata": {},
+ "outputs": []
}
],
"metadata": {}
diff --git a/not_so_obvious_python_stuff.ipynb b/not_so_obvious_python_stuff.ipynb
index ab5feb2..5497f91 100644
--- a/not_so_obvious_python_stuff.ipynb
+++ b/not_so_obvious_python_stuff.ipynb
@@ -1,7 +1,7 @@
{
"metadata": {
"name": "",
- "signature": "sha256:ce4b364bfb6414a1b40e25c6ed5320cec6bdbb11d75ce3e44632fe27504ace7e"
+ "signature": "sha256:35f23d6f2bbaa131a262533ed080684ed53fc0260430780f248c09af8c645759"
},
"nbformat": 3,
"nbformat_minor": 0,
@@ -69,7 +69,8 @@
"- [List slicing using indexes that are \"out of range](#out_of_range_slicing)\n",
"- [Reusing global variable names and UnboundLocalErrors](#unboundlocalerror)\n",
"- [Creating copies of mutable objects](#copy_mutable)\n",
- "- [Key differences between Python 2 and 3](#python_differences)"
+ "- [Key differences between Python 2 and 3](#python_differences)\n",
+ "- [Function annotations - What are those `->`'s in my Python code?](#function_annotation)"
]
},
{
@@ -2109,6 +2110,228 @@
"language": "python",
"metadata": {},
"outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
\n",
+ "\n",
+ "## Function annotations - What are those `->`'s in my Python code?\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Have you ever seen any Python code that used colons inside the parantheses of a function definition?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "def foo1(x: 'insert x here', y: 'insert x^2 here'):\n",
+ " print('Hello, World')\n",
+ " return"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [],
+ "prompt_number": 8
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "And what about the fancy arrow here?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "def foo2(x, y) -> 'Hi!':\n",
+ " print('Hello, World')\n",
+ " return"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [],
+ "prompt_number": 10
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Q: Is this valid Python syntax? \n",
+ "A: Yes!\n",
+ " \n",
+ " \n",
+ "Q: So, what happens if I *just call* the function? \n",
+ "A: Nothing!\n",
+ " \n",
+ "Here is the proof!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "foo1(1,2)"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [
+ {
+ "output_type": "stream",
+ "stream": "stdout",
+ "text": [
+ "Hello, World\n"
+ ]
+ }
+ ],
+ "prompt_number": 9
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "foo2(1,2) "
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [
+ {
+ "output_type": "stream",
+ "stream": "stdout",
+ "text": [
+ "Hello, World\n"
+ ]
+ }
+ ],
+ "prompt_number": 11
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**So, those are function annotations ... ** \n",
+ "- the colon for the function parameters \n",
+ "- the arrow for the return value \n",
+ "\n",
+ "You probably will never make use of them (or at least very rarely). Usually, we write good function documentations below the function as a docstring - or at least this is how I would do it (okay this case is a little bit extreme, I have to admit):"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "def is_palindrome(a):\n",
+ " \"\"\"\n",
+ " Case-and punctuation insensitive check if a string is a palindrom.\n",
+ " \n",
+ " Keyword arguments:\n",
+ " a (str): The string to be checked if it is a palindrome.\n",
+ " \n",
+ " Returns `True` if input string is a palindrome, else False.\n",
+ " \n",
+ " \"\"\"\n",
+ " stripped_str = [l for l in my_str.lower() if l.isalpha()]\n",
+ " return stripped_str == stripped_str[::-1]\n",
+ " "
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "However, function annotations can be useful to indicate that work is still in progress in some cases. But they are optional and I see them very very rarely.\n",
+ "\n",
+ "As it is stated in [PEP3107](http://legacy.python.org/dev/peps/pep-3107/#fundamentals-of-function-annotations):\n",
+ "\n",
+ "1. Function annotations, both for parameters and return values, are completely optional.\n",
+ "\n",
+ "2. Function annotations are nothing more than a way of associating arbitrary Python expressions with various parts of a function at compile-time.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The nice thing about function annotations is their `__annotations__` attribute, which is dictionary of all the parameters and/or the `return` value you annotated."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "foo1.__annotations__"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [
+ {
+ "metadata": {},
+ "output_type": "pyout",
+ "prompt_number": 17,
+ "text": [
+ "{'y': 'insert x^2 here', 'x': 'insert x here'}"
+ ]
+ }
+ ],
+ "prompt_number": 17
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [
+ "foo2.__annotations__"
+ ],
+ "language": "python",
+ "metadata": {},
+ "outputs": [
+ {
+ "metadata": {},
+ "output_type": "pyout",
+ "prompt_number": 18,
+ "text": [
+ "{'return': 'Hi!'}"
+ ]
+ }
+ ],
+ "prompt_number": 18
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**When are they useful?**"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Function annotations can be useful for a couple of things \n",
+ "- Documentation in general\n",
+ "- pre-condition testing\n",
+ "- [type checking](http://legacy.python.org/dev/peps/pep-0362/#annotation-checker)\n",
+ " \n",
+ "..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "collapsed": false,
+ "input": [],
+ "language": "python",
+ "metadata": {},
+ "outputs": []
}
],
"metadata": {}