{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h1 align=\"center\">Functions</h1>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Scope rules"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"a = 0\n",
"m = 0\n",
"n = 0\n",
"x = 0\n",
"\n",
"print('PRINT 0: a =', a,\n",
" ' m =', m, ' n =', n,\n",
" ' x =', x)\n",
"\n",
"def f_1():\n",
" m = 1\n",
" global n\n",
" n = 1\n",
" x = 1\n",
" y = 1\n",
" z = 1\n",
" print('PRINT 1: a =', a,\n",
" ' m =', m, ' n =', n,\n",
" ' x =', x, ' y =', y, ' z =', z)\n",
" \n",
" def f_2():\n",
" global m\n",
" m = 2\n",
" # Cannot write:\n",
" # nonlocal n\n",
" global n\n",
" n = 2\n",
" global p\n",
" p = 2\n",
" x = 2\n",
" nonlocal y\n",
" y = 2\n",
" # Cannot write:\n",
" # nonlocal u\n",
" print('PRINT 2: a =', a,\n",
" ' m =', m, ' n =', n, ' p =', p,\n",
" ' x =', x, ' y =', y, ' z =', z)\n",
"\n",
" def f_3():\n",
" nonlocal x\n",
" x = 3\n",
" nonlocal y\n",
" y = 3\n",
" nonlocal z\n",
" z = 3\n",
" print('PRINT 3: a =', a,\n",
" ' m =', m, ' n =', n, ' p =', p,\n",
" ' x =', x, ' y =', y, ' z =', z)\n",
"\n",
" f_3()\n",
" print('PRINT 4: a =', a,\n",
" ' m =', m, ' n =', n, ' p =', p,\n",
" ' x =', x, ' y =', y, ' z =', z)\n",
"\n",
" f_2()\n",
" print('PRINT 5: a =', a,\n",
" ' m =', m, ' n =', n, ' p =', p,\n",
" ' x =', x, ' y =', y, ' z =', z)\n",
"\n",
"f_1()\n",
"print('PRINT 6: a =', a,\n",
" ' m =', m, ' n =', n, ' p =', p,\n",
" ' x =', x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Closures (factory functions)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def v1_multiply_by(m):\n",
" def multiply(n):\n",
" return n * m\n",
" return multiply\n",
"\n",
"multiply_by_7 = v1_multiply_by(7)\n",
"print(multiply_by_7(4))\n",
"\n",
"def v2_multiply_by(m):\n",
" return lambda n: n * m\n",
"\n",
"multiply_by_7 = v2_multiply_by(7)\n",
"print(multiply_by_7(4))\n",
"\n",
"def multiplications_between_0_and_9():\n",
" multiply_by = []\n",
" for m in range(10):\n",
" # If \"lambda n, m = m: n * m\" is replaced by \"lambda n, m: n * m\"\n",
" # then all mulplications are by 9\n",
" multiply_by.append(lambda n, m = m: n * m)\n",
" return multiply_by\n",
"\n",
"multiply_by = multiplications_between_0_and_9()\n",
"multiply_by_7 = multiply_by[7]\n",
"print(multiply_by_7(4))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Function states"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"from random import randrange\n",
"\n",
"def randomly_odd_or_even_random_digit():\n",
" odd = randrange(2)\n",
" if odd:\n",
" def random_odd_or_random_even_digit():\n",
" return randrange(1, 10, 2)\n",
" else:\n",
" def random_odd_or_random_even_digit():\n",
" return randrange(0, 10, 2)\n",
" random_odd_or_random_even_digit.odd = odd\n",
" return random_odd_or_random_even_digit\n",
"\n",
"for i in range(10):\n",
" random_odd_or_random_even_digit = randomly_odd_or_even_random_digit()\n",
" if random_odd_or_random_even_digit.odd:\n",
" print('Will be a random odd digit.... ', random_odd_or_random_even_digit())\n",
" else:\n",
" print('Will be a random even digit... ', random_odd_or_random_even_digit())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Function parameters:\n",
"- first variables without default values, if any,\n",
"- then variables with default values, if any,\n",
"- then, possibly,\n",
" - either a starred variable to\n",
" - gather values and assign them to variables of the first and second type beyond those that have been assigned a nonnamed value, if any, provided none of these variables is assigned a named value,\n",
" - and to store an arbitray number of nonnamed values beyond the previous ones, if any,\n",
" - or only a star,\n",
"- if a starred variable or only a star is present, then variables for required named values (so called \"keyword-only arguments\"), if any, with or without defaults (actually the defaults make the associated keyword-only arguments not truly required and these variables could be part of the second group),\n",
"- then a double starred variable to store an arbitray number of named values, if any."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Function arguments:\n",
"- all nonnamed values, if any, first,\n",
"- at most one double starred dictionnary last,\n",
"- at most one starred iterable of values, and named values, if any, in-between.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def f1(a, b, c = 3, d = 4, e = 5, f = 6):\n",
" print(a, b, c, d, e, f)\n",
"\n",
"f1(11, 12, 13, 14, 15, 16)\n",
"f1(11, 12, 13, *(14, 15, 16))\n",
"f1(11, *(12, 13, 14), **{'f': 16, 'e': 15})\n",
"f1(11, 12, 13, e = 15)\n",
"f1(11, c = 13, b = 12, e = 15)\n",
"f1(11, c = 13, *(12,), e = 15)\n",
"f1(11, *(12, 13), e = 15)\n",
"f1(11, e = 15, *(12, 13))\n",
"f1(11, f = 16, e = 15, b = 12, c = 13)\n",
"f1(11, f = 16, **{'e': 15, 'b': 12, 'c': 13})\n",
"f1(11, *(12, 13), e = 15, **{'f': 16, 'd': 14})\n",
"f1(11, e = 15, *(12,), **{'f': 16, 'd': 14})\n",
"f1(11, f = 16, *(12, 13), e = 15, **{'d': 14})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def f2(*x):\n",
" print(x)\n",
"\n",
"f2()\n",
"f2(11)\n",
"f2(11, 12, *(13, 14, 15))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def f3(*x, a, b = -2, c):\n",
" print(x, a, b, c)\n",
"\n",
"f3(c = 23, a = 21)\n",
"f3(11, 12, a = 21, **{'b': 22, 'c': 23})\n",
"f3(11, *(12, 13), c = 23, a = 21)\n",
"f3(11, 12, 13, c = 23, *(14, 15), **{'a': 21})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def f4(*, a, b = -2, c):\n",
" print(a, b, c)\n",
"\n",
"f4(c = 23, a = 21)\n",
"f4(**{'a': 21, 'b': 22, 'c': 23})\n",
"f4(c = 23, **{'a': 21})\n",
"f4(a = 21, **{'c': 23, 'b': 22})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def f5(**x):\n",
" print(x)\n",
"\n",
"f5()\n",
"f5(a = 11, b = 12)\n",
"f5(**{'a': 11, 'b': 12, 'c': 13})\n",
"f5(a = 11, c = 12, e = 15, **{'b': 13, 'd': 14})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def f6(a, b, c, d = 4, e = 5, *x, m, n = -2, o, **z):\n",
" print(a, b, c, d, e, x, m, n, o, z)\n",
"\n",
"# Cannot replace \"*(12,)\" by \"*(12, 21)\"\n",
"f6(11, t = 40, e = 15, *(12,), o = 33, c = 13, m = 31, u = 41,\n",
" **{'v': 42, 'w': 43}) \n",
"# Cannot replace \"*(13, 14)\" by \"*(13, 14, 21)\"\n",
"f6(11, 12, u = 41, m = 31, t = 40, e = 15, *(13, 14), o = 33,\n",
" **{'v': 42, 'w': 43}) \n",
"f6(11, u = 41, o = 33, *(12, 13, 14, 15, 21, 22), n = 32, t = 40, m = 31,\n",
" **{'v': 42, 'w': 43}) \n",
"f6(11, 12, 13, n = 32, t = 40, *(14, 15, 21, 22, 23), o = 33, u = 41, m = 31,\n",
" **{'v': 42, 'w': 43})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Function annotations"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def f(w: str, a: int, b: int = -2, x: float = -3.) -> int:\n",
" if w == 'incorrect_return_type':\n",
" return '0'\n",
" return 0\n",
"\n",
"from inspect import signature\n",
"\n",
"def type_check(function, *args, **kwargs):\n",
" '''Assumes that \"function\" has nothing but variables possibly with defaults\n",
" as arguments and has type annotations for all arguments and the returned value.\n",
" Checks whether a combination of values and named values is correct,\n",
" and in case it is whether those values are of the appropriate types,\n",
" and in case they are whether the returned value is of the appropriate type.\n",
" '''\n",
" good_arguments = True\n",
" argument_type_errors = ''\n",
" parameters = list(reversed(function.__code__.co_varnames))\n",
" if len(args) > len(parameters):\n",
" print('Incorrect sequence of arguments')\n",
" return\n",
" for argument in args:\n",
" parameter = parameters.pop()\n",
" if not isinstance(argument, function.__annotations__[parameter]):\n",
" argument_type_errors += ('{} should be of type {}\\n'\n",
" .format(parameter, function.__annotations__[parameter]))\n",
" good_arguments = False\n",
" for argument in kwargs:\n",
" if not argument in parameters:\n",
" print('Incorrect sequence of arguments')\n",
" return\n",
" if not isinstance(kwargs[argument], function.__annotations__[argument]):\n",
" argument_type_errors += ('{} should be of type {}\\n'\n",
" .format(argument, function.__annotations__[argument]))\n",
" good_arguments = False\n",
" parameters.remove(argument)\n",
" # Make sure that all parameters left are given a default value.\n",
" if any([parameter for parameter in parameters\n",
" if signature(f).parameters[parameter].default is\n",
" signature(f).parameters[parameter].empty]):\n",
" print('Incorrect sequence of arguments')\n",
" return\n",
" if good_arguments:\n",
" if isinstance(function(*args, **kwargs), function.__annotations__['return']):\n",
" print('All good')\n",
" else:\n",
" (print('The returned value should be of type {}'\n",
" .format(function.__annotations__['return'])))\n",
" else:\n",
" print(argument_type_errors, end = '')\n",
"\n",
"for args, kwargs in [(('0', 1, 2, 3.), {}),\n",
" (('0', 1, 2), {'x': 3.}),\n",
" (('0', 1), {'b': 2, 'x': 3.}),\n",
" (('0',), {'x': 3., 'a': 1, 'b': 2}),\n",
" ((), {'x': 3., 'w': '0', 'a': 1}),\n",
" (('0', 1, 2), {}),\n",
" (('0',), {}),\n",
" (('0'), {'x': 3.}),\n",
" (('0', 1, 2, 3., 4), {}),\n",
" (('incorrect_return_type', 1, 2, 3.), {'x' : 3}),\n",
" (('incorrect_return_type', 1, 2), {'y': 3}),\n",
" (('0', 1), {'x': 3, 'c': 2}),\n",
" ((), {'a': 1, 'b': 2,'x': 3}),\n",
" ((0, 1, 2, 3.), {}),\n",
" (('0', 1., 2, 3), {'w': 'incorrect_return_type'}),\n",
" (('incorrect_return_type', 1, 2), {'x': 3}),\n",
" ((0, 1), {'b': 2., 'x': 3.}),\n",
" ((0,), {'x': 3, 'a': 1., 'b': 2.}),\n",
" ((), {'x': 3, 'w': 0, 'a': 1.}),\n",
" (('incorrect_return_type', 1, 2, 3.), {})]:\n",
" print('Testing {}, {}:'.format(args, kwargs))\n",
" type_check(f, *args, **kwargs)\n",
" print()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Mutable versus immutable default values"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def append_one_v1(L = []):\n",
" L.append(1)\n",
" return L\n",
"\n",
"def append_one_v2(L = None):\n",
" if L == None:\n",
" L = []\n",
" L.append(1)\n",
" return L\n",
"\n",
"for i in range(5):\n",
" print(append_one_v1([0]))\n",
"print()\n",
"for i in range(5):\n",
" print(append_one_v1())\n",
"print()\n",
"for i in range(5):\n",
" print(append_one_v2([0]))\n",
"print()\n",
"for i in range(5):\n",
" print(append_one_v2())"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.4.3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Resource created Wednesday 02 September 2015, 11:04:59 AM, last modified Wednesday 02 September 2015, 02:32:23 PM.
file: functions.ipynb