{
 "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


Back to top

COMP9021 15s2 (Principles of Programming) is powered by WebCMS3
CRICOS Provider No. 00098G