diff --git a/03.identity.ipynb b/03.identity.ipynb index c003608..019152b 100644 --- a/03.identity.ipynb +++ b/03.identity.ipynb @@ -10,7 +10,7 @@ "toc-hr-collapsed": true }, "source": [ - "## Python Objects & References\n", + "# Python Objects & References\n", "\n", "Everything in Python is an `object`. An object is a piece of memory with values & associated operations.\n", "\n", @@ -60,7 +60,7 @@ } }, "source": [ - "#### objects are typed, not variables\n", + "## objects are typed, not variables\n", "\n", "![shared_ref2.png](attachment:shared_ref2.png)\n", " -- Learning Python 2013" @@ -75,7 +75,7 @@ } }, "source": [ - "### Shared references\n", + "## Shared references\n", "\n", "Setting a variable to a new value does not alter the original.\n", "\n", @@ -271,7 +271,7 @@ "id": "99744fac-c1d9-4532-a7d4-0dcbc1a0d2a3", "metadata": {}, "source": [ - "### Garbage Collection\n", + "## Garbage Collection\n", "\n", "Python is a garbage collected language. \n", "\n", @@ -414,7 +414,7 @@ "id": "9a48460e-a342-4d18-8383-b84483a3a010", "metadata": {}, "source": [ - "### list / string example revisited" + "### list / string mutability revisited" ] }, { @@ -458,7 +458,7 @@ } }, "source": [ - "### Object Creation\n", + "### Aside: Object Creation Quirk\n", "\n", " Each time you generate a new value in your script by running an expression, Python creates a new object (i.e., a chunk of memory) to represent that value.\n", " \n", @@ -523,7 +523,7 @@ } }, "source": [ - "### Copying\n", + "## copy & deepcopy\n", "\n", "If `y = x` does not make a copy, how can we get one?\n", "\n", diff --git a/04.functions.ipynb b/04.functions.ipynb index f3dbc4f..d56a993 100644 --- a/04.functions.ipynb +++ b/04.functions.ipynb @@ -5,7 +5,7 @@ "id": "eeb9e8e4", "metadata": {}, "source": [ - "## Functions" + "# Functions" ] }, { diff --git a/05.functional-programming.ipynb b/05.functional-programming.ipynb new file mode 100644 index 0000000..74e227d --- /dev/null +++ b/05.functional-programming.ipynb @@ -0,0 +1,892 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "de726aba-1fb3-4b2e-be01-825ced7a9093", + "metadata": {}, + "source": [ + "# Functional Programming\n", + "\n", + "The style of programming we've been doing is called **imperative** or **procedural**. Statements run in sequence and change a program's state.\n", + "\n", + "As we said early on, Python is multi-paradigm. \n", + "\n", + "> \"[...] practicality beats purity.\"\n", + "> \n", + "> - The Zen of Python\n", + "\n", + "Languages like LISP, Haskell, Racket are purely functional & differ significantly from procedural & object-oriented languages.\n", + "\n", + "Functional programming uses a more mathematical definition of functions. Instead of the recipe model of procedural programming, mathematical functions take input(s) and return an output. \n", + "\n", + "These functions do not have the concept of \"state\", that is, calling a function in math creates a mapping from inputs to outputs.\n", + "\n", + "When we call `sin(x)` we do not speak of it modifying its inputs, just returning a value.\n", + "\n", + "Similarly, when we workin a functional style we'll often write smaller functions that we chain together, instead of long procedures that rely on internal state.\n", + "\n", + "Python has many features that stem from pure functional languages & support functional programming:\n", + "\n", + "- Functions as first class objects\n", + "- Lambda expressions\n", + "- map/filter\n", + "- `functools`\n", + "- comprehensions\n", + "\n", + "## Functions are \"first-class objects\"\n", + "\n", + "A key feature of Python that makes it possible to write code in the functional style is the fact that functions are objects. (Everything in Python is an object.)\n", + "\n", + "This means functions don't have special rules about how they can be used, any variable can reference a function. (Remember, a variable is an association between a name & object.)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72bee260-b4d1-4c61-a689-8799d4dfb7c6", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def echo(message):\n", + " print(message)\n", + " print(message)\n", + " \n", + "print(f\"echo = {echo}\")\n", + "print(f\"type(echo) = {type(echo)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39ee1708-c3ec-47ed-9c87-2124fa55b57f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# we can assign other names to objects, including functions\n", + "\n", + "x = echo\n", + "\n", + "x(\"hello\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a175699-fd00-4e69-a534-2d25085550d2", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "id(x), id(echo)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52de62a9-af2f-4fbe-becf-2c315ddb9c77", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# we can also store functions in other types\n", + "\n", + "func_list = [print, echo, print, echo]\n", + "for i, func in enumerate(func_list):\n", + " func(i)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6cad8105-8a71-4b8a-926c-dfa0f635e7ad", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# dictionaries too\n", + "func_mapping = {False: print, True: echo}\n", + "\n", + "print_twice = True\n", + "func_mapping[True](\"twice\")\n", + "\n", + "print_twice = False\n", + "func_mapping[print_twice](\"once\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54247b2d-d5fe-4bbb-990a-bbaf6660f89d", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d89416fb-e0e7-48ca-9ca7-9fea5525b273", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# we can pass functions into other functions\n", + "\n", + "def add(a, b):\n", + " return a + b\n", + "\n", + "def sub(a, b):\n", + " return a - b\n", + "\n", + "def perform_op(op_func, a, b):\n", + " return op_func(a, b)\n", + "\n", + "print(\"add, 3, 4 = \", perform_op(add, 3, 4))\n", + "print(\"sub, 3, 4 = \", perform_op(sub, 3, 4))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0192ae3-d175-4140-a8a9-ea664ee1e015", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# and we can return functions from other functions\n", + "\n", + "def get_op(name):\n", + " if name == \"div\":\n", + " def f(a, b):\n", + " return a / b\n", + " elif name == \"mod\":\n", + " def f(a, b):\n", + " return a % b\n", + " return f" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f558df5-c1ae-4a20-9820-8a6d83878302", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "fn = get_op(\"mod\")\n", + "perform_op(fn, 10, 3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9039813a-a943-40e1-802f-f230547ffa2d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "x = [(\"Nick\", 1), (\"Yusong\", 9), (\"Emma\", 100)]\n", + "\n", + "def negate(y):\n", + " return -y\n", + "\n", + "x.sort(key=lambda item: item[1])\n", + "print(x)\n", + "\n", + "#x.sort(key=negate)\n", + "#print(x)" + ] + }, + { + "cell_type": "markdown", + "id": "06fdddbe-0903-452c-8528-e5a0b8489f50", + "metadata": {}, + "source": [ + "## lambda functions\n", + "\n", + "Python also provides another way to generate function objects.\n", + "\n", + "These are called lambda functions (aka anonymous functions), which:\n", + "\n", + "- Are expressions that return a function object that can be called later without providing a name (hence ``anonymous\")\n", + "- Can be used in places where def statement is not syntactically legal (inside a literal list, inlined as a function argument, etc.)\n", + "\n", + "The body of an lambda function is a single expression, not a block of statements. The body is similar to a return statement in a def statement.\n", + "\n", + "```python\n", + "\n", + "lambda arg1, arg2: expression\n", + "\n", + "# essentially the same as\n", + "\n", + "def __(arg1, arg2):\n", + " return expression\n", + "```\n", + "\n", + "(0 or more arguments, but *must* have an expression)" + ] + }, + { + "cell_type": "markdown", + "id": "bf3e3782-2baf-4a04-8a23-252d39ad5dd3", + "metadata": {}, + "source": [ + "## Reminder: expressions vs. statements\n", + "\n", + "Everything in Python is either an expression or a statement. \n", + "\n", + "An expression evaluates to a value, examples include:\n", + "\n", + "* `42`\n", + "* `\"hello world\"`\n", + "* `10 * 5`\n", + "* `f(1, 2, 3)`\n", + "* `[1, 2, 3]`\n", + "* `l[0]` \n", + "* `lambda arg1, arg2: arg1 + arg2`\n", + "\n", + "Notice that all of these could be found on the right hand side of an assignment (e.g. `x = 10 * 5`)\n", + "\n", + "Expresssions are valid in assignment, function calls, sequence values, etc. (Anywhere a value is needed.)\n", + "\n", + "```\n", + "# in assignment\n", + "x = 42\n", + "x = 10 * 5\n", + "x = [1, 2, 3]\n", + "\n", + "# in function calls\n", + "f(42)\n", + "f(10 * 5)\n", + "f([1, 2, 3])\n", + "\n", + "# in complex types\n", + "[42, [1, 2, 3], lambda x: x**2]\n", + "{10*5: f(10, 5)}\n", + "```\n", + "\n", + "To contrast, statements perform an action.\n", + "\n", + "* `x = 1`\n", + "* `if x: ...`\n", + "* `def f(a): ...` \n", + "* `import math`\n", + "\n", + "They are prohibted where types are required:\n", + "\n", + "```\n", + " # not allowed\n", + "x = if y > 0: \n", + " 7\n", + "\n", + "z = def f(a): \n", + " ...\n", + "```\n", + "\n", + "A statement will often have multiple expressions within it. Many statements (but not all) use indented blocks.\n", + "\n", + "When it comes to `lambda`:\n", + "* a `lambda` defines a function that maps input to a single expression, `def` can be used if more was needed\n", + "* a `lambda` is itself an expression, it can be used anywhere other expresssions are needed" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68f51efb-9a62-4303-afe7-3639be9cc395", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# can fit places a function definition can't\n", + "# such as being used as a parameter\n", + "perform_op(lambda a, b: a * b, 5, 6)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15e0c8eb-d8af-4e85-a53d-06820961b5e8", + "metadata": {}, + "outputs": [], + "source": [ + "lambda s: s.upper()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39bf652e-f85d-4a66-96bf-0ae21054be26", + "metadata": {}, + "outputs": [], + "source": [ + "# can be assigned to a variable\n", + "mul = lambda a, b: a * b\n", + "mul(5, 6)\n", + "\n", + "# same as\n", + "def mul2(a, b):\n", + " return a * b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1eb1c524-30e1-4b20-b2a9-7b078e906c61", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "type(mul), type(mul2)" + ] + }, + { + "cell_type": "markdown", + "id": "51a501aa-4533-4d34-bb6d-8185521cf8e7", + "metadata": {}, + "source": [ + "General rule: If you're giving a lambda a name, use a function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "425bb2b5-bb3a-448e-a6fb-9060579f588a", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# common use case\n", + "names = [\"adam\", \"Ziwe\", \"Bo\", \"JENNY\"]\n", + "names.sort()\n", + "print(names) # case sensitive, lower-case a comes after Z" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a1477f21-65e6-4925-8da7-8321cb801eac", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "names.sort(key = lambda x: x.upper())\n", + "print(names)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a773d32c-b061-410a-a4e4-f7afe8a83529", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "308a3691-8873-4166-afec-089a653333d4", + "metadata": {}, + "source": [ + "## Functional Methods\n", + "\n", + "Python also has several built in methods that are useful when writing programs with a functional mindset.\n", + "\n", + "`map`, `filter`, `functools`\n", + "\n", + "#### `map(function, iterable1, [...iterableN])`\n", + "\n", + "Returns a new iterable that calls `function` with parameters from `iterable1 ... iterableN`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e2768f5-8817-4dfc-8ff5-72a774f499fa", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def add_two(x):\n", + " return x + 2\n", + "\n", + "for x in map(add_two, [1, 2, 3]):\n", + " print(x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd940ce1-c28a-4646-8846-f199f586cad8", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "help(map)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04106e30-95df-432a-b6b0-40fcc58f51e5", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "x = list(map(add_two, [1, 2, 3]))\n", + "print(x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fba295ed-9dcb-4cbb-8b7e-3b0ff2965639", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# commonly used with lambdas\n", + "\n", + "for x in map(lambda x, y, z: x * y + z, (\"A\", \"B\", \"C\"), [\"!\", \"?\", \".\"]):\n", + " print(x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4e1d7f9-c111-44ff-8525-de147f90aa56", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# operator module contains all of the common operators\n", + "import operator\n", + "\n", + "operator.sub(20, 5)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6383ce1-6e06-44a4-beb2-1e946b81c483", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "list(map(operator.sub, [20, 19], [10, 9]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b58441e4-ba95-43e4-8151-dd25e1c7efd1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# the result of `map` is an iterable\n", + "\n", + "# possible to pass into set or list \n", + "# or anywhere you can pass an iterable\n", + "set(map(lambda x: x * 3, (\"A\", \"B\", \"C\")))" + ] + }, + { + "cell_type": "markdown", + "id": "a58bbdf5-afb7-466b-886e-618ea0411ab3", + "metadata": {}, + "source": [ + "#### `filter(function, iterable)` \n", + "\n", + "returns an iterable that contains all items from iterable for which `function(item)` returns True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7eaab05d-2b8e-45fa-ad97-565c2edac0f6", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "list(map(lambda s: s.title(), filter(str.isupper, [\"a\", \"ABC\", \"AbCdeF\", \"XYZ\"])))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4a69097-c30c-4096-b69b-f3fa89a1bc7f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "list(filter(lambda s: s.isupper(), [\"a\", \"ABC\", \"AbCdeF\", \"XYZ\"]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6852f961-f20d-4c82-8da4-c7bdcfc1ae4b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "list(map(lambda s: s.lower(), filter(lambda s: s.isupper(), [\"a\", \"ABC\", \"AbCdeF\", \"XYZ\"])))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a195957c-0e89-4d3e-9b85-ace9e1f84e5d", + "metadata": {}, + "outputs": [], + "source": [ + "g = (x**2 for x in filter(lambda x: x % 2 != 0, range(20)))\n", + "list(g)" + ] + }, + { + "cell_type": "markdown", + "id": "aab35319-a066-414f-a0b5-d66412d41061", + "metadata": {}, + "source": [ + "#### functools" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2529705-fd60-45ed-ae13-0a77f745c201", + "metadata": {}, + "outputs": [], + "source": [ + "import functools\n", + "[name for name in dir(functools) if name[0].islower()]" + ] + }, + { + "cell_type": "markdown", + "id": "67d3bc6f-f3a4-4b7e-984f-87d22ad3925f", + "metadata": {}, + "source": [ + "``functools.reduce(function, iterable[, initializer])``\n", + "\n", + "Apply ``function`` to pairs of items successively and return a single value as the result. You can optionally specify the initial value.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a623edc8-08cb-41d0-8b2c-fd99619fed73", + "metadata": {}, + "outputs": [], + "source": [ + "import functools \n", + "import operator \n", + "\n", + "#accumulator = 0\n", + "#for item in my_list:\n", + "# accumulator += item\n", + "\n", + "# 1st iteration: Call operator.add(1,2) -> 3 \n", + "# 2nd iteration: Call operator.add(3,3) -> 6 \n", + "# 3rd iteration: Call operator.add(6,4) -> 10 \n", + "# final result = 10 \n", + "functools.reduce(operator.add, [1,2,3,4])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5081e0e6-424b-472b-b0b0-f0c2bfa1344e", + "metadata": {}, + "outputs": [], + "source": [ + "names = [\"Ben\", \"Martha\", \"Susan\"]\n", + "# 1st iteration: call f(0, \"Ben\") -> 0 + len(\"Ben\") -> 3\n", + "# 2nd iteration: call f(3, \"Martha\") -> 3 + len(\"Martha\") -> 9\n", + "# 3rd iteration: call f(9, \"Susan\") -> 9 + len(\"Susan\") -> 14\n", + "functools.reduce(lambda a, b: a + len(b), names, 0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6fd2afda-b07f-45f6-9a82-6bc50665af6c", + "metadata": {}, + "outputs": [], + "source": [ + "# What happens if you pass in an initial value \n", + "# 1st iteration: Call operator.mul(2,1) -> 2 \n", + "# 2nd iteration: Call operator.mul(2,2) -> 4 \n", + "# 3rd iteration: Call operator.mul(4,3) -> 12 \n", + "# 4th iteration: Call operator.mul(12,4) -> 48 \n", + "# Final result = 48 \n", + "functools.reduce(operator.mul, [1,2,3,4], 0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "74e7a581-3f79-4be3-ba9d-f354b1df13a1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "functools.reduce(lambda a,b: a+b, [], 0)" + ] + }, + { + "cell_type": "markdown", + "id": "b0dea67f-aaf8-43aa-a166-7bbfd4d2496d", + "metadata": {}, + "source": [ + "```functools.partial(func, *args, **kwargs)```\n", + "\n", + "`functools.partial` returns a new function that \"binds\" any passed args & kwargs, and leaves other parameters unbound." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a23eb2c-8324-4ff1-beb2-bca7ff5dbbe1", + "metadata": {}, + "outputs": [], + "source": [ + "import operator\n", + "operator.mul(2, 10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70988dc5-1a32-4316-bb9a-d4be646dd2c2", + "metadata": {}, + "outputs": [], + "source": [ + "import functools\n", + "negate = functools.partial(operator.mul, -1)\n", + "negate(5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b2d87c2-903a-4b48-a012-3e3b0b03584f", + "metadata": {}, + "outputs": [], + "source": [ + "def calls_twice(f):\n", + " print(f())\n", + " print(f())\n", + " \n", + "\n", + "g = functools.partial(operator.mul, 4, 4)\n", + "#print(g())\n", + "calls_twice(g)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e2ffbc6-e05f-401e-b569-273c61f6d514", + "metadata": {}, + "outputs": [], + "source": [ + "print_ex = functools.partial(print, \"x\", sep=\"!\")\n", + "print_ex(\"a\", \"b\", \"c\")\n", + "print(\"x\", \"a\", \"b\", \"c\", sep=\"!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e9be6b5-0a68-4de6-8289-31fb5095d31f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "print_foo = functools.partial(print, foo=\"x\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10c4769b-7b1f-4fbc-924d-8b3e5de7fb93", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "print_foo(\"hello\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "318556fb-eafa-44af-bcfd-0848b87b6e18", + "metadata": {}, + "outputs": [], + "source": [ + "def request_page(url, verify, cache=True, send_cookies=False, https_only=True):\n", + " pass\n", + "\n", + "secure_request = functools.partial(request_page, verify=True, https_only=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b4c5678-2525-4822-93e3-77dd0f40213b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "secure_request(\"\", verify=False)\n", + "sec" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "157ff803-8809-481e-bff4-1fa06d067963", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "5ba68ff2-42fd-441b-ac44-9d51bd9b6d8b", + "metadata": {}, + "source": [ + "## List Comprehensions\n", + "\n", + "Generate a new list from an existing iterable.\n", + "\n", + "Same syntax as generator expression but inside `[]`:\n", + "\n", + "```python\n", + "new_list = [expression for var in iterable]\n", + "\n", + "# or \n", + "\n", + "new_list = [expression for var in iterable if condition]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79029822-694a-445d-9776-48e05e94733b", + "metadata": {}, + "outputs": [], + "source": [ + "powers_of_two = [2 ** n for n in range(10)]\n", + "print(powers_of_two)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe7d9640-165c-4887-a9f0-9e411fc8e031", + "metadata": {}, + "outputs": [], + "source": [ + "# possible to nest comprehensions, but beware readability\n", + "faces = (\"K\", \"Q\", \"J\")\n", + "suits = (\"♠\", \"♣\", \"♦\", \"♥\")\n", + "cards = [(face + suit) for face in faces for suit in suits if face != \"K\"]\n", + "print(cards)" + ] + }, + { + "cell_type": "markdown", + "id": "94a7b169-7930-4df5-a1ed-76f6bb0df14c", + "metadata": {}, + "source": [ + "## Set & Dict Comprehensions\n", + "\n", + "Also possible to make `set` and `dict` comprehensions by using `{}`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24213ab6-3c6e-45df-8bb9-93b2d69c10fa", + "metadata": {}, + "outputs": [], + "source": [ + "powers_of_two_set = {2 ** n for n in [1,1,2,2,3,3,3,4,4,4]}\n", + "print(powers_of_two_set)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95f3d657-39aa-4803-8fc7-4e736ebc5b20", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "powers_of_two_mapping = {n: f(n) for n in range(5) if n > 0}\n", + "print(powers_of_two_mapping)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7139c632-97cf-49a5-8abf-5b7516c1a401", + "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" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}