diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2c6601 --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +coverage_html_report/ +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints/ +Untitled*.ipynb diff --git a/MagicMethods.ipynb b/MagicMethods.ipynb index 9239be9..7b3f6c9 100644 --- a/MagicMethods.ipynb +++ b/MagicMethods.ipynb @@ -1,57 +1,329 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Syntax and the Corresponding Magic" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "with x as y:\n", + " \"body\"\n", + "```\n", + "\n", + "---\n", + "\n", + "```\n", + "y = x.__enter__()\n", + "try:\n", + " \"body\"\n", + "except BaseException as exc:\n", + " x.__exit__(*sys.exc_info()) # type(exc), exc, traceback\n", + "```\n", + "\n", + "---\n", + "---\n", + "\n", + "```\n", + "for y in x:\n", + " print(f\"I like {y}\")\n", + "```\n", + "\n", + "---\n", + "\n", + "```\n", + "try:\n", + " ix = x.__iter__()\n", + " while True:\n", + " y = next(ix)\n", + " print(f\"I like {y}\")\n", + "except StopIteration:\n", + " pass\n", + "```" + ] + }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 437, "metadata": {}, "outputs": [], "source": [ - "class X:\n", - " def __add__(self, other):\n", - "# return 5\n", - " return NotImplemented\n", - " \n", - "class Y:\n", - " def __radd__(self, other):\n", - " return 6" + "class Mgr:\n", + " def __init__(self, name):\n", + " self.name = name\n", + " \n", + " def __enter__(self):\n", + " print('enter')\n", + " \n", + " def __exit__(self, exc_type, exc_info, tb):\n", + " print('exit!')" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 438, "metadata": {}, "outputs": [ { - "ename": "TypeError", - "evalue": "unsupported operand type(s) for +: 'X' and 'X'", + "name": "stdout", + "output_type": "stream", + "text": [ + "enter\n", + "exit!\n" + ] + }, + { + "ename": "NameError", + "evalue": "name 'aaaaaa' is not defined", "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[0;32m----> 1\u001b[0;31m \u001b[0mX\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'X' and 'X'" + "\u001b[0;31mNameError\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 1\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mMgr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'nick'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0maaaaaa\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'aaaaaa' is not defined" + ] + } + ], + "source": [ + "with Mgr('nick'):\n", + " aaaaaa" + ] + }, + { + "cell_type": "code", + "execution_count": 344, + "metadata": {}, + "outputs": [], + "source": [ + "class Base:\n", + " def __init__(self, name):\n", + " self.name = name" + ] + }, + { + "cell_type": "code", + "execution_count": 372, + "metadata": {}, + "outputs": [], + "source": [ + "b = Base('NaOH')" + ] + }, + { + "cell_type": "code", + "execution_count": 373, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.Base at 0x7fbbc22b8ac8>" + ] + }, + "execution_count": 373, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b" + ] + }, + { + "cell_type": "code", + "execution_count": 374, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<__main__.Base object at 0x7fbbc22b8ac8>\n" ] } ], "source": [ - "X() + X()" + "print(repr(b))" ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": {}, "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "x = X()\n", - "y = Y()\n", + "```\n", "\n", - "z = x + y\n", "\n", - "try:\n", - " z = x.__add__(y)\n", - "except TypeError:\n", - " z = y.__radd__(x)" + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Stringy Types" + ] + }, + { + "cell_type": "code", + "execution_count": 375, + "metadata": {}, + "outputs": [], + "source": [ + "class Stringy:\n", + " def __init__(self, name):\n", + " self.name = name\n", + " \n", + " def __repr__(self) -> str:\n", + " return f\"{self.__class__.__name__}({self.name!r})\"\n", + " \n", + " def __str__(self) -> str:\n", + " return f\"It's name...is {self.name}\"" + ] + }, + { + "cell_type": "code", + "execution_count": 376, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Stringy('apple')" + ] + }, + "execution_count": 376, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a = Stringy('apple')\n", + "a" + ] + }, + { + "cell_type": "code", + "execution_count": 377, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"Stringy('apple')\"" + ] + }, + "execution_count": 377, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "repr(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 378, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "\"It's name...is apple\"" + ] + }, + "execution_count": 378, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "str(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [], + "source": [ + "class StringyToo:\n", + " def __init__(self, name):\n", + " self.name = name\n", + " \n", + " def to_string(self):\n", + " return f\"It's name...is {self.name}\"" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.StringyToo at 0x7fbbc26b6c88>" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b = StringyToo('cheese')\n", + "b" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "\"It's name...is cheese\"" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b.to_string()" ] }, { @@ -61,32 +333,758 @@ "outputs": [], "source": [] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Quacks like...\n", + "\n", + "String-like objects can be used in place of other strings" + ] + }, + { + "cell_type": "code", + "execution_count": 321, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'I have an object. <__main__.Base object at 0x7fbbc22e49b0>.'" + ] + }, + "execution_count": 321, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "f\"I have an object. {b}.\"" + ] + }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 90, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "(True, False)" + "\"I have an object. It's name...is apple. It was made with Stringy('apple')\"" ] }, - "execution_count": 23, + "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "class A:\n", - " def __init__(self, val):\n", - " self.val = val\n", + "f\"I have an object. {a}. It was made with {a!r}\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", "\n", - " def __lt__(self, other):\n", - " return self.val < other.val \n", "\n", "\n", - "A(3) < A(5), A(5) < A(0)" + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Addable Types\n", + "\n", + "Implementing the mathematical magic methods can let you use any of the infix operators to manipulate your objects as makes sense.\n", + "\n", + " x + y x ** y x & y x << y\n", + " x - y x // y x | y x >> y\n", + " x * y x % y x ^ y\n", + " x / y x @ y " + ] + }, + { + "cell_type": "code", + "execution_count": 406, + "metadata": {}, + "outputs": [], + "source": [ + "class Mathy(Stringy):\n", + " def __add__(self, other) -> str:\n", + " return f\"{self.name} and {other.name}\"" + ] + }, + { + "cell_type": "code", + "execution_count": 166, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'coke and mentos'" + ] + }, + "execution_count": 166, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Mathy(\"coke\") + Mathy(\"mentos\")" + ] + }, + { + "cell_type": "code", + "execution_count": 167, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "must be str, not Mathy", + "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[0;32m----> 1\u001b[0;31m \u001b[0mMathy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"eggs\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mMathy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"spam\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mMathy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"cheese\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m: must be str, not Mathy" + ] + } + ], + "source": [ + "Mathy(\"eggs\") + Mathy(\"spam\") + Mathy(\"cheese\")" + ] + }, + { + "cell_type": "code", + "execution_count": 199, + "metadata": {}, + "outputs": [], + "source": [ + "class Addy(Stringy):\n", + " def __add__(self, other) -> 'Addy':\n", + " return Addy(f\"{self.name} and {other.name}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 173, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Addy('eggs and spam and cheese')" + ] + }, + "execution_count": 173, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Addy(\"eggs\") + Addy(\"spam\") + Addy(\"cheese\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Builtins that Add\n", + "\n", + "The built-in `sum()` uses `+` to add objects together. It uses a start value to " + ] + }, + { + "cell_type": "code", + "execution_count": 407, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on built-in function sum in module builtins:\n", + "\n", + "sum(iterable, start=0, /)\n", + " Return the sum of a 'start' value (default: 0) plus an iterable of numbers\n", + " \n", + " When the iterable is empty, return the start value.\n", + " This function is intended specifically for use with numeric values and may\n", + " reject non-numeric types.\n", + "\n" + ] + } + ], + "source": [ + "help(sum)" + ] + }, + { + "cell_type": "code", + "execution_count": 194, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "unsupported operand type(s) for +: 'int' and 'Addy'", + "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[0;32m----> 1\u001b[0;31m \u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mAddy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"eggs\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mAddy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"spam\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mAddy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"cheese\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mAddy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'funny walks'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'Addy'" + ] + } + ], + "source": [ + "sum([Addy(\"eggs\"), Addy(\"spam\"), Addy(\"cheese\"), Addy('funny walks')])" + ] + }, + { + "cell_type": "code", + "execution_count": 196, + "metadata": {}, + "outputs": [], + "source": [ + "class Addy2(Stringy):\n", + " def __add__(self, other) -> 'Addy2':\n", + " return Addy2(f\"{self.name} and {other.name}\")\n", + " \n", + " def __radd__(self, other) -> 'Addy2':\n", + " if not other:\n", + " return self" + ] + }, + { + "cell_type": "code", + "execution_count": 197, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Addy2('eggs and spam and cheese and funny walks')" + ] + }, + "execution_count": 197, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sum([Addy2(\"eggs\"), Addy2(\"spam\"), Addy2(\"cheese\"), Addy2('funny walks')])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Orderable Types" + ] + }, + { + "cell_type": "code", + "execution_count": 384, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Stringy('Capaldi'),\n", + " Stringy('Eccleston'),\n", + " Stringy('Smith'),\n", + " Stringy('Tennant'),\n", + " Stringy('Whittaker')]" + ] + }, + "execution_count": 384, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "doctors = [\n", + " Stringy('Eccleston'), \n", + " Stringy('Tennant'), \n", + " Stringy('Smith'), \n", + " Stringy('Capaldi'), \n", + " Stringy('Whittaker'),\n", + "]\n", + "\n", + "sorted(doctors, key=lambda i: i.name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 385, + "metadata": {}, + "outputs": [], + "source": [ + "class Comparable(Stringy):\n", + " def __lt__(self, other):\n", + " return self.name < other.name" + ] + }, + { + "cell_type": "code", + "execution_count": 386, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 386, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Comparable('apple') < Comparable('banana')" + ] + }, + { + "cell_type": "code", + "execution_count": 276, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 276, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Comparable('pear') < Comparable('banana')" + ] + }, + { + "cell_type": "code", + "execution_count": 387, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Comparable('Eccleston'),\n", + " Comparable('Tennant'),\n", + " Comparable('Smith'),\n", + " Comparable('Capaldi'),\n", + " Comparable('Whittaker')]" + ] + }, + "execution_count": 387, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "doctors = [Comparable(d.name) for d in doctors]\n", + "doctors" + ] + }, + { + "cell_type": "code", + "execution_count": 388, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Comparable('Capaldi'),\n", + " Comparable('Eccleston'),\n", + " Comparable('Smith'),\n", + " Comparable('Tennant'),\n", + " Comparable('Whittaker')]" + ] + }, + "execution_count": 388, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted(doctors)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Container Types" + ] + }, + { + "cell_type": "code", + "execution_count": 401, + "metadata": {}, + "outputs": [], + "source": [ + "import re\n", + "\n", + "import requests\n", + "\n", + "\n", + "def get_xkcd_hotlink(comic_number):\n", + " response = requests.get(f\"https://xkcd.com/{comic_number}/\")\n", + " match = re.search(\n", + " r\"Image URL \\(for hotlinking/embedding\\):\\s*(?Phttp.*(jpg|png))\", \n", + " response.text,\n", + " )\n", + " if not match:\n", + " return None\n", + "\n", + " src = match.groupdict()[\"url\"]\n", + " return src \n", + "\n", + "\n", + "class XKCDContainer: \n", + " def __getitem__(self, key):\n", + " url = get_xkcd_hotlink(key)\n", + " if url is None:\n", + " raise KeyError(\"couldn't find XKCD comic with that number\")\n", + " return url\n", + " \n", + " def __contains__(self, key):\n", + " return get_xkcd_hotlink(key) is not None" + ] + }, + { + "cell_type": "code", + "execution_count": 402, + "metadata": {}, + "outputs": [], + "source": [ + "xkcd_container = XKCDContainer()" + ] + }, + { + "cell_type": "code", + "execution_count": 403, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'https://imgs.xkcd.com/comics/responsible_behavior.png'" + ] + }, + "execution_count": 403, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "xkcd_container[364]" + ] + }, + { + "cell_type": "code", + "execution_count": 404, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 404, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1000 in xkcd_container" + ] + }, + { + "cell_type": "code", + "execution_count": 405, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 405, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "10000 in xkcd_container" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Proprietary Magic" + ] + }, + { + "cell_type": "code", + "execution_count": 398, + "metadata": {}, + "outputs": [], + "source": [ + "class XKCDComic:\n", + " def __init__(self, url):\n", + " self.url = url\n", + "\n", + " def _repr_html_(self):\n", + " return f\"\"\n", + "\n", + "\n", + "class XKCDViewer(XKCDContainer):\n", + " def __getitem__(self, key):\n", + " return XKCDComic(super().__getitem__(key))" + ] + }, + { + "cell_type": "code", + "execution_count": 399, + "metadata": {}, + "outputs": [], + "source": [ + "xkcd = XKCDViewer()" + ] + }, + { + "cell_type": "code", + "execution_count": 400, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "<__main__.XKCDComic at 0x7fbbc22e2860>" + ] + }, + "execution_count": 400, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "xkcd[843]" ] }, { diff --git a/README.md b/README.md new file mode 100644 index 0000000..4b37d8c --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# Magic Methods + +Slides: https://docs.google.com/presentation/d/13rnvQ7w2YT3WQKgDDAEd7Unlf67WcgzYVN3uGt-vJP8/edit?usp=sharing + +Notebook: https://github.com/nicktimko/chipy-magicmethods/blob/master/MagicMethods.ipynb + +--- + +Notebook and slides content is MIT-licensed. +Slides style is copyright Telnyx LLC.