{ "cells": [ { "cell_type": "markdown", "id": "dressed-fighter", "metadata": {}, "source": [ "# pyg.base.Dict\n", "\n", "There are a few existing dict-extensions similar to Dict (a nice example is https://github.com/mewwts/addict) but Dict has a little more up its sleeve.\n", "\n", "## initialization" ] }, { "cell_type": "code", "execution_count": 1, "id": "competitive-australia", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1, 'b': 2, 'c': 3}" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from pyg import *\n", "Dict(a = 1, b = 2, c = 3)" ] }, { "cell_type": "code", "execution_count": 2, "id": "japanese-surveillance", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1, 'b': 2, 'c': 3}" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 1)(b = 2, c = 3)" ] }, { "cell_type": "code", "execution_count": 3, "id": "hispanic-rebel", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1, 'b': 2, 'c': 3}" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 1)(b = 2)(c = lambda a, b: a+b)" ] }, { "cell_type": "code", "execution_count": 4, "id": "hourly-malawi", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1, 'b': 2, 'c': 3}" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 1) + dict(b = 2, c = 3)" ] }, { "cell_type": "markdown", "id": "statistical-promise", "metadata": {}, "source": [ "## members access" ] }, { "cell_type": "code", "execution_count": 5, "id": "mechanical-arabic", "metadata": {}, "outputs": [], "source": [ "d = Dict(a = 1, b = 2, c = 3)" ] }, { "cell_type": "code", "execution_count": 6, "id": "engaging-budapest", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.a" ] }, { "cell_type": "code", "execution_count": 7, "id": "available-porter", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d['a', 'b']" ] }, { "cell_type": "code", "execution_count": 8, "id": "bulgarian-comparison", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1, 'b': 2}" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d[['a', 'b']]" ] }, { "cell_type": "markdown", "id": "likely-diagnosis", "metadata": {}, "source": [ "But the fun starts when Dict allows you to access **functions** of its keys:" ] }, { "cell_type": "code", "execution_count": 9, "id": "challenging-guyana", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d[lambda a, b: a + b]" ] }, { "cell_type": "markdown", "id": "single-trace", "metadata": {}, "source": [ "It is important to note that be making d['a', 'b'] access both 'a' and 'b' keys, we abandon the right to have tuples as keys." ] }, { "cell_type": "code", "execution_count": 10, "id": "organic-imperial", "metadata": {}, "outputs": [], "source": [ "d = Dict({('a','b') : 1})\n", "import pytest\n", "with pytest.raises(KeyError): # Dict will be trying to grab 'a' and 'b' separately\n", " d[('a','b')]" ] }, { "cell_type": "markdown", "id": "cathedral-disclosure", "metadata": {}, "source": [ "## adding" ] }, { "cell_type": "code", "execution_count": 11, "id": "harmful-triumph", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1, 'b': 3, 'c': 4}" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 1, b = 2) + dict(b = 3, c = 4) # like .update() but not in-place" ] }, { "cell_type": "markdown", "id": "boolean-determination", "metadata": {}, "source": [ "But addition is subtly different from update in the case of tree structure:" ] }, { "cell_type": "code", "execution_count": 12, "id": "tight-bulgaria", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1, 'b': {'c': 'new value for b.c but keep b.d', 'd': 3, 'e': 4}, 'x': 1}" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree = Dict(a = 1, b = Dict(c = 2, d = 3))\n", "update = dict(x = 1, b = dict(c = 'new value for b.c but keep b.d', e = 4))\n", "tree+update" ] }, { "cell_type": "markdown", "id": "seven-handle", "metadata": {}, "source": [ "Tree updating is actually important enough to have its own function that can operate on dict-trees" ] }, { "cell_type": "code", "execution_count": 13, "id": "fatty-quarterly", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1, 'b': {'c': 'new value for b.c but keep b.d', 'd': 3, 'e': 4}, 'x': 1}" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree = dict(a = 1, b = dict(c = 2, d = 3)) # I only use dicts\n", "tree_update(tree, update) # but I can still update it like a tree" ] }, { "cell_type": "markdown", "id": "challenging-replacement", "metadata": {}, "source": [ "## subtracting\n", "You can subtract keys or list of keys" ] }, { "cell_type": "code", "execution_count": 23, "id": "equivalent-special", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'b': 2, 'c': 3}" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 'remove me', b = 2, c = 3) - 'a' # subtracting a key" ] }, { "cell_type": "code", "execution_count": 24, "id": "killing-appendix", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'c': 3}" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 'I am gone', b = 'and so am I', c = 3) - ['a', 'b'] # subtracting a collection of keys" ] }, { "cell_type": "code", "execution_count": 28, "id": "preceding-auckland", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1, 'b': {'d': 'but keep me'}, 'c': 3}" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tree = Dict(a = 1, b = Dict(c = 'delete me', d = 'but keep me'), c = 3)\n", "tree - ('b', 'c') ## subtracting a branch in a tree using a tuple, possible because we know ('b', 'c') is never a node" ] }, { "cell_type": "markdown", "id": "overhead-lesbian", "metadata": {}, "source": [ "## modifying the keys: rename" ] }, { "cell_type": "code", "execution_count": 29, "id": "elder-footage", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'prefix_a': 1, 'prefix_b': 2}" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 1, b = 2).rename('prefix_') # need to be done sufficient" ] }, { "cell_type": "code", "execution_count": 30, "id": "curious-education", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a_suffix': 1, 'b_suffix': 2}" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 1, b = 2).rename('_suffix')" ] }, { "cell_type": "code", "execution_count": 31, "id": "returning-documentary", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'A': 1, 'B': 2}" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 1, b = 2).rename(upper)" ] }, { "cell_type": "code", "execution_count": 33, "id": "naval-encounter", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'Abraham': 1, 'Barbara': 2, 'c': 3}" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 1, b = 2, c = 3).rename(a = 'Abraham', b = 'Barbara')" ] }, { "cell_type": "markdown", "id": "phantom-adult", "metadata": {}, "source": [ "## modifying the values: do" ] }, { "cell_type": "code", "execution_count": 34, "id": "greater-riverside", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1, 'b': 4, 'c': 9}" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 1, b = 2, c = 3).do(lambda x: x**2) # modify all values using function" ] }, { "cell_type": "code", "execution_count": 37, "id": "silver-armor", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 0, 'b': 3, 'c': 8}" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 1, b = 2, c = 3).do([lambda x: x**2, lambda x: x-1]) # modify all values using list of function" ] }, { "cell_type": "code", "execution_count": 40, "id": "global-strategy", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 0, 'b': 3, 'c': 3}" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Dict(a = 1, b = 2, c = 3).do([lambda x: x**2, lambda x: x-1], 'a', 'b') # modify selected keys using list of function" ] }, { "cell_type": "markdown", "id": "available-reproduction", "metadata": {}, "source": [ "## Dict can store a calculation flow\n", "Being able to access function of members means we can think of a Dict as a container of variables. \n", "Consider this code:" ] }, { "cell_type": "code", "execution_count": 17, "id": "everyday-convertible", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.388888888888889" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def func(a, b):\n", " c = a + b\n", " d = b + c\n", " e = a/b + d/c\n", " f = (d+e)/c\n", " return f\n", "func(1,2)" ] }, { "cell_type": "markdown", "id": "prescribed-fossil", "metadata": {}, "source": [ "How can we keep track of our calculations and debug it easily? Consider rewriting this:" ] }, { "cell_type": "code", "execution_count": 18, "id": "qualified-opinion", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1,\n", " 'b': 2,\n", " 'c': 3,\n", " 'd': 5,\n", " 'e': 2.166666666666667,\n", " 'f': 2.388888888888889}" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = Dict(a = 1, b = 2)\n", "x = x(c = lambda a, b: a + b)\n", "x = x(d = lambda b, c: b + c)\n", "x = x(e = lambda a,b,c,d : a/b + d/c)\n", "x = x(f = lambda c,d,e: (d+e)/c)\n", "x" ] }, { "cell_type": "markdown", "id": "distinct-present", "metadata": {}, "source": [ "We have all the internals of the function exposed and we are able to separate calculation flow and data easily:" ] }, { "cell_type": "code", "execution_count": 19, "id": "great-consultation", "metadata": {}, "outputs": [], "source": [ "calculation_pipeline = dict(c = lambda a, b: a + b,\n", " d = lambda b, c: b + c,\n", " e = lambda a,b,c,d : a/b + d/c,\n", " f = lambda c,d,e: (d+e)/c)\n", "\n", "initial_values = Dict(a = 1, b = 2)\n" ] }, { "cell_type": "code", "execution_count": 20, "id": "respiratory-right", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1,\n", " 'b': 2,\n", " 'c': 3,\n", " 'd': 5,\n", " 'e': 2.166666666666667,\n", " 'f': 2.388888888888889}" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "initial_values(**calculation_pipeline)" ] }, { "cell_type": "markdown", "id": "tamil-appeal", "metadata": {}, "source": [ "You can see in pyg.base.dictable tutorial how this is extended" ] } ], "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.8.5" } }, "nbformat": 4, "nbformat_minor": 5 }