{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Higher-Order Functions\n", "They simply have a function in the type signature.\n", "\n", "How do you represent this in MyPy?\n", "\n", "`typing.Callable`.\n", "\n", ">typing.Callable\n", "Callable type; `Callable[[BarType], FooType]` is a function of `(BarType) -> FooType`.\n", ">\n", ">The subscription syntax must always be used with exactly two values: the argument list and the return type. The argument list must be a list of types or an ellipsis; the return type must be a single type.\n", ">\n", ">There is no syntax to indicate optional or keyword arguments; such function types are rarely used as callback types. `Callable[..., FooType]` (literal ellipsis) can be used to type hint a callable taking any number of arguments and returning `FooType`. A plain `Callable` is equivalent to `Callable[..., Any]`, and in turn to `collections.abc.Callable`.\n", "\n", "Okay. Well in turn then what is `collections.abc.Callable`?\n", "\n", "[The Python docs for `collections.abc`](https://docs.python.org/3/library/collections.abc.html) states:\n", "\n", "> This module provides abstract base classes that can be used to test whether a class provides a particular interface; for example, whether it is hashable or whether it is a mapping.\n", "\n", "Further down this spec we see \n", "\n", " > `class collections.abc.Callable`\n", " >\n", " > ABCs for classes that provide respectively the methods `__contains__()`, `__hash__()`, `__len__()`, and `__call__()`.\n", " \n", "***Whaat? Why?????***\n", "\n", "> `object.__contains__(self, item)`\n", ">\n", "> Called to implement membership test operators. Should return true if item is in self, false otherwise. For mapping objects, this should consider the keys of the mapping rather than the values or the key-item pairs.\n", ">\n", "> For objects that don’t define __contains__(), the membership test first tries iteration via __iter__(), then the old sequence iteration protocol via __getitem__(), see this section in the language reference.\n", "\n", "Okay. Can we use this thing?" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class Evens:\n", " def __contains__(self, item):\n", " return item % 2 == 0\n", "\n", "\n", "2 in Evens()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cool. But why would this matter to `Callable`?\n", "\n", "My best guess is that it's for inspecting the signature dynamically." ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "scrolled": true }, "outputs": [ { "ename": "TypeError", "evalue": "argument of type 'function' is not iterable", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;34m\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;36m2\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: argument of type 'function' is not iterable" ] } ], "source": [ "def f(a1: int, a2: str, a3: bool) -> str:\n", " return \"\"\n", "\n", "2 in f" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# . . . 🤯 😾\n", "\n", "Omg. Never do **this**:\n", "\n", "- *class* `collections.abc.Container`\n", "- *class* `collections.abc.Hashable`\n", "- *class* `collections.abc.Sized`\n", "- *class* `collections.abc.Callable`\n", " - ABCs for classes that provide respectively the methods `__contains__()`, `__hash__()`, `__len__()`, and `__call__()`.\n", "\n", "\n", "Just write it like this:\n", "\n", "- *class* `collections.abc.Container`\n", " - ABC for classes that provide the method `__contains__()`.\n", " \n", "\n", "- *class* `collections.abc.Hashable`\n", " - ABC for classes that provide the method `__hash__()`.\n", "\n", "\n", "- *class* `collections.abc.Sized`\n", " - ABC for classes that provide the method `__len__()`.\n", "\n", "\n", "- *class* `collections.abc.Callable`\n", " - ABC for classes that provide the method `__call__()`.\n", " \n", " \n", " Maybe I should submit this as a documenation bug to Python.\n", " \n", " \n", " So here is the thing we care about here \n", " \n", "> `object.__call__(self[, args...])`\n", "> Called when the instance is “called” as a function; if this method is defined, `x(arg1, arg2, ...)` is a shorthand for `x.__call__(arg1, arg2, ...)`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.7.5" } }, "nbformat": 4, "nbformat_minor": 4 }