From 902fbc70da361ffbf2e4cab4be56bd872ed3d2a8 Mon Sep 17 00:00:00 2001 From: James Turk Date: Sun, 27 Oct 2024 19:16:17 -0500 Subject: [PATCH] two helper notebooks --- more-decorators.ipynb | 283 ++++++++++++++++++++++++++ thinking-in-list-comprehensions.ipynb | 240 ++++++++++++++++++++++ 2 files changed, 523 insertions(+) create mode 100644 more-decorators.ipynb create mode 100644 thinking-in-list-comprehensions.ipynb diff --git a/more-decorators.ipynb b/more-decorators.ipynb new file mode 100644 index 0000000..addc1c7 --- /dev/null +++ b/more-decorators.ipynb @@ -0,0 +1,283 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "02e68cf1", + "metadata": {}, + "source": [ + "# More Decorator Examples\n", + "\n", + "Some additional examples beyond what is in 08.decorators." + ] + }, + { + "cell_type": "markdown", + "id": "b985a33b", + "metadata": {}, + "source": [ + "## Modifying Arguments within newfunc" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "31c291f2", + "metadata": {}, + "outputs": [], + "source": [ + "def reverse_args(func):\n", + " def newfunc(*args):\n", + " # within newfunc we are able to write whatever we'd like\n", + " # we could decide that we want to reverse the arguments\n", + " reversed_args = reversed(args)\n", + " return func(*reversed_args)\n", + " return newfunc\n", + "\n", + "\n", + "@reverse_args\n", + "def print_args(*args):\n", + " for arg in args:\n", + " print(arg)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "413cfac8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "2\n", + "1\n" + ] + } + ], + "source": [ + "print_args(1, 2, 3)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "95e01cf9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.2" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@reverse_args\n", + "def divide(a, b):\n", + " return a / b\n", + "\n", + "divide(10, 2)" + ] + }, + { + "cell_type": "markdown", + "id": "d055880d", + "metadata": {}, + "source": [ + "## Example: Authorization" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "1590c5de", + "metadata": {}, + "outputs": [], + "source": [ + "# perhaps we want a function that checks if a user can perform an action\n", + "def auth_required(func):\n", + " \n", + " # list of allowed users. in practice, we'd look this up in a database\n", + " allowed_users = (\"lauren\", \"mitch\")\n", + " \n", + " def newfunc(*args, **kwargs):\n", + " # here, we're actually using an argument within newfunc\n", + " # by checking if it is in the kwargs dictionary\n", + " if kwargs.get(\"auth_user\") in allowed_users:\n", + " func(*args, **kwargs)\n", + " else:\n", + " print(\"ACCESS DENIED\")\n", + " return newfunc\n", + "\n", + "# these functions must also accept auth_user so that the above call to func(*args, **kwargs)\n", + "# doesn't send an invalid parameter through\n", + "@auth_required\n", + "def withdraw_funds(account, amount, auth_user):\n", + " print(f\"withdrew {amount} funds from account={account}\")\n", + "\n", + "@auth_required\n", + "def delete_account(account, auth_user):\n", + " print(\"deleted\", account)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "f9e8bcd0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "withdrew 100 funds from account=jim\n" + ] + } + ], + "source": [ + "withdraw_funds(\"jim\", 100, auth_user=\"lauren\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "77a82ae4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ACCESS DENIED\n" + ] + } + ], + "source": [ + "delete_account(\"kevin\", auth_user=\"jim\")" + ] + }, + { + "cell_type": "markdown", + "id": "cf9a611a", + "metadata": {}, + "source": [ + "## Modifying Keyword Parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "90161162", + "metadata": {}, + "outputs": [], + "source": [ + "# if we didn't want auth_user to be passed through, we'd make a small modification to newfunc\n", + "\n", + "def auth_required(func): \n", + " allowed_users = (\"lauren\", \"mitch\")\n", + " \n", + " def newfunc(*args, auth_user, **kwargs):\n", + " # newfunc now requires auth_user, and passes through all *other* parameters\n", + " if auth_user in allowed_users:\n", + " func(*args, **kwargs)\n", + " else:\n", + " print(\"ACCESS DENIED\")\n", + " return newfunc\n", + "\n", + "# auth_user is no longer seen in the definition of these functions \n", + "# but it can be passed in since the newfunc returned from auth_required accepts it\n", + "@auth_required\n", + "def withdraw_funds(account, amount):\n", + " print(f\"withdrew {amount} funds from account={account}\")\n", + "\n", + "@auth_required\n", + "def delete_account(account):\n", + " print(\"deleted\", account)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "ee4cabe7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "withdrew 100 funds from account=jim\n" + ] + } + ], + "source": [ + "withdraw_funds(\"jim\", 100, auth_user=\"lauren\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "a22a86d9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ACCESS DENIED\n" + ] + } + ], + "source": [ + "delete_account(\"kevin\", auth_user=\"jim\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dca4b1ec", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.15" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/thinking-in-list-comprehensions.ipynb b/thinking-in-list-comprehensions.ipynb new file mode 100644 index 0000000..6e71a59 --- /dev/null +++ b/thinking-in-list-comprehensions.ipynb @@ -0,0 +1,240 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "54ee872b-aa95-4e8a-b22f-7a42c7d3c0cf", + "metadata": {}, + "source": [ + "# Thinking in list comprehensions\n", + "\n", + "Here is a way of thinking about list comprehensions that may help you write more complex comprehensions in a natural way:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "80df68a2-5a72-4b44-9c72-8dffffc57dfe", + "metadata": {}, + "outputs": [], + "source": [ + "def make_powers_lc(n, inputs):\n", + " \"\"\"\n", + " Given list of inputs, return each input raised to the 1st-Nth power\n", + " \n", + " e.g.\n", + " >>> make_powers_lc(4, range(10))\n", + " [[0, 0, 0, 0],\n", + " [1, 1, 1, 1],\n", + " [2, 4, 8, 16],\n", + " [3, 9, 27, 81],\n", + " [4, 16, 64, 256],\n", + " [5, 25, 125, 625],\n", + " [6, 36, 216, 1296],\n", + " [7, 49, 343, 2401],\n", + " [8, 64, 512, 4096],\n", + " [9, 81, 729, 6561]]\n", + " \"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8eb3928f", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "1caa3d73", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[1]]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 1) start with shape: \n", + "# Output will be a list of list of ints, \n", + "# so create simplest version of that\n", + "def make_powers_lc(n, inputs):\n", + " return [[1]]\n", + "make_powers_lc(4, range(10))" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "cc3309a8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 2) expand outer list comprehension to have correct number of elements\n", + "# using inputs as foundation, we haven't modified the first term yet\n", + "def make_powers_lc(n, inputs):\n", + " return [[1] for x in inputs]\n", + "make_powers_lc(4, range(10))" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "8a531ebc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[1, 1, 1, 1],\n", + " [1, 1, 1, 1],\n", + " [1, 1, 1, 1],\n", + " [1, 1, 1, 1],\n", + " [1, 1, 1, 1],\n", + " [1, 1, 1, 1],\n", + " [1, 1, 1, 1],\n", + " [1, 1, 1, 1],\n", + " [1, 1, 1, 1],\n", + " [1, 1, 1, 1]]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 3) Now expand inner list to have correct number of elements.\n", + "def make_powers_lc(n, inputs):\n", + " return [[1 for y in range(n)] for x in inputs]\n", + "make_powers_lc(4, range(10))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "80135012", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[1, 0, 0, 0],\n", + " [1, 1, 1, 1],\n", + " [1, 2, 4, 8],\n", + " [1, 3, 9, 27],\n", + " [1, 4, 16, 64],\n", + " [1, 5, 25, 125],\n", + " [1, 6, 36, 216],\n", + " [1, 7, 49, 343],\n", + " [1, 8, 64, 512],\n", + " [1, 9, 81, 729]]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 4) Fix initial term to do calculation\n", + "def make_powers_lc(n, inputs):\n", + " return [[x**y for y in range(n)] for x in inputs]\n", + "make_powers_lc(4, range(10))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "513b22ba", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[0, 0, 0, 0],\n", + " [1, 1, 1, 1],\n", + " [2, 4, 8, 16],\n", + " [3, 9, 27, 81],\n", + " [4, 16, 64, 256],\n", + " [5, 25, 125, 625],\n", + " [6, 36, 216, 1296],\n", + " [7, 49, 343, 2401],\n", + " [8, 64, 512, 4096],\n", + " [9, 81, 729, 6561]]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 5) With correct shape, make modifications to ranges/etc. as needed\n", + "def make_powers_lc(n, inputs):\n", + " return [[x**y for y in range(1, n+1)] for x in inputs]\n", + "make_powers_lc(4, range(10))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15faca48", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.15" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}