{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "First-Class Functions\n", "\n", "[First-Class Function](https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function): A programming language is said to have First-class functions when functions in that language are treated like any other variable. For example, in such a language, a function can be passed as an argument to other functions, can be returned by another function and can be assigned as a value to a variable.\n", "\n", "[First-Class Citizen](https://en.wikipedia.org/wiki/First-class_citizen): a first-class citizen (also type, object, entity, or value) in a given programming language is an entity which supports all the operations generally available to other entities. These operations typically include being passed as an argument, returned from a function, modified, and assigned to a variable.\n", "\n", "We'll go through some examples to understand what first-class functions are. Note this notebook uses Python 3.6.0." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "8\n" ] } ], "source": [ "def cube(number: int) -> int:\n", " \"\"\" Return the cube of a number. \"\"\"\n", " \n", " return number ** 3\n", "\n", "cube_two = cube(2) # Call the function, set cube_two to the value returned\n", "\n", "print(cube) # It says cube is a function\n", "print(cube_two) # The value stored in cube_two" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[4, 64, 8.0]\n", "{'two_cubed': 8, 'five_cubed': 125}\n" ] } ], "source": [ "nums = [4, cube(4), cube(4) / cube(4) ** 0.5] # returned values as list elements\n", "print(nums)\n", "\n", "cube_dict = {'two_cubed': cube(2), 'five_cubed': cube(5)} # as dict values\n", "print(cube_dict)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we'll see how we can set a variable to the cube() function." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n" ] } ], "source": [ "make_cube = cube # Take out those parentheses\n", "\n", "print(cube)\n", "print(make_cube) # make_cube points to the cube() function" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, the variable `make_cube` can be used as a function, like so:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "64\n" ] } ], "source": [ "print(cube)\n", "print(make_cube(4))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Functions can be passed as arguments and returned by other functions.\n", "\n", "A [higher-order function](https://en.wikipedia.org/wiki/Higher-order_function) accepts other functions as arguments or returns functions as its result.\n", "\n", "`map` is an example: it takes a function and an iterable as its arguments, and it applies the function to each value of that iterable and then returns a new iterable of those results.\n", "\n", "Here's an example of `map` taking a function (`int`) as an argument." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['1', '2', '3']\n", "[1, 2, 3]\n" ] } ], "source": [ "str_nums = ['1', '2', '3']\n", "one, two, three = map(int, str_nums) # similar to [int(n) for n in str_nums]\n", "\n", "print(str_nums)\n", "print([one, two, three])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`reduce` is another example: it applies a function of two arguments cumulatively to the items of an iterable. Let's look at an example to see what this means." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n" ] } ], "source": [ "from functools import reduce\n", "\n", "cumu_diff = reduce(lambda x, y: x - y, [3, 2, 1]) # cumulative difference\n", "print(cumu_diff)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's create a map-like function (well, kind of)." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2, 3]\n" ] } ], "source": [ "from typing import Callable, Sequence, Iterable\n", "\n", "def map_it(func: Callable, seq: Sequence) -> Iterable:\n", " \"\"\" Apply a given function to a sequence and yield the result. \"\"\"\n", " for item in seq:\n", " yield func(item)\n", "\n", "str_nums = ['1', '2', '3']\n", "one, two, three = map_it(int, str_nums) # same as map(int, str_nums)\n", "\n", "print([one, two, three])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's see how to return a function from another function." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", ".print_message at 0x05D8C270>\n", "Hello, E.T.!\n", "None\n" ] } ], "source": [ "def greet(name: str) -> str:\n", " \"\"\" Return a callable function with the given name. \"\"\"\n", " \n", " def print_message():\n", " \"\"\" A callable that prints a message to stdout. \"\"\"\n", " print(\"Hello, {}!\".format(name))\n", " \n", " return print_message # returning the function, not calling it\n", "\n", "greet_et = greet('E.T.') # greet_et points to print_message()\n", "\n", "print(greet)\n", "print(greet_et)\n", "print(greet_et())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here's another example." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "

This is a small paragraph.

\n" ] } ], "source": [ "def make_paragraph(tag: str) -> str:\n", " \"\"\" Return a callable function with the given tag. \"\"\"\n", " \n", " def wrapper(text: str) -> str:\n", " \"\"\" Return text wrapped with a tag. \"\"\"\n", " return '<{0}>{1}'.format(tag, text)\n", " \n", " return wrapper\n", "\n", "\n", "para_one = make_paragraph('p')\n", "\n", "print(para_one('This is a small paragraph.')) # returns '

This is a small paragraph.

'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In conclusoin, in Python, functions are first-class objects. You can pass functions around as arguments to other functions, store them as dictionary or list values, or have a function return another function.\n", "\n", "We've seen several ways to use functions in Python. Happy programming!" ] } ], "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.6.0" } }, "nbformat": 4, "nbformat_minor": 2 }