1278 lines
29 KiB
Plaintext
1278 lines
29 KiB
Plaintext
{
|
|
"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",
|
|
"**state** can be thought of as the status of all variables at a given time. Imperative programming relies heavily on functions updating 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, and Racket are purely functional & differ significantly from procedural & object-oriented languages.\n",
|
|
"\n",
|
|
"Functional programming uses a definition of functions more compatible with the mathematical definition. 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 = f()\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",
|
|
"fn(100, 5)\n",
|
|
"#perform_op(fn, 10, 3)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "c898e181-1fcd-477e-b6bf-573544ed6170",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"x = [(\"Nick\", 1), (\"Nick\", -100), (\"Yusong\", 9000), (\"Emma\", 100)]\n",
|
|
"\n",
|
|
"def negate(y):\n",
|
|
" return -y[1]\n",
|
|
"\n",
|
|
"def second_key(item):\n",
|
|
" return item[1]\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "ff9cfd44-8a22-4c83-98a6-4420ce651238",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"x.sort(key=negate)\n",
|
|
"print(x)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "9422326e-37ad-4ffe-8e03-4a0bd76df9de",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"help(sorted)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "73f8aee0-8a13-43cf-b565-96285891dd4f",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"second_key(x[0])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "8c3c8074-4696-483a-9a16-238caec889f6",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"x.sort()\n",
|
|
"print(x)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "3b13f2e4-f269-482a-b0b4-ed1831fd6e1b",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def second_key(item):\n",
|
|
" return item[1]\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": "9b6748b0-9fb0-4664-86c6-bc35e4c5d9e2",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"sorted([\"abc\", \"Abc\", \"ABC\", \"AbC\"], key=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": 2,
|
|
"id": "3e2768f5-8817-4dfc-8ff5-72a774f499fa",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"called add_two 1\n",
|
|
"3\n",
|
|
"called add_two 2\n",
|
|
"4\n",
|
|
"called add_two 3\n",
|
|
"5\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"def add_two(x):\n",
|
|
" print(\"called 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": 1,
|
|
"id": "cd940ce1-c28a-4646-8846-f199f586cad8",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Help on class map in module builtins:\n",
|
|
"\n",
|
|
"class map(object)\n",
|
|
" | map(func, *iterables) --> map object\n",
|
|
" | \n",
|
|
" | Make an iterator that computes the function using arguments from\n",
|
|
" | each of the iterables. Stops when the shortest iterable is exhausted.\n",
|
|
" | \n",
|
|
" | Methods defined here:\n",
|
|
" | \n",
|
|
" | __getattribute__(self, name, /)\n",
|
|
" | Return getattr(self, name).\n",
|
|
" | \n",
|
|
" | __iter__(self, /)\n",
|
|
" | Implement iter(self).\n",
|
|
" | \n",
|
|
" | __next__(self, /)\n",
|
|
" | Implement next(self).\n",
|
|
" | \n",
|
|
" | __reduce__(...)\n",
|
|
" | Return state information for pickling.\n",
|
|
" | \n",
|
|
" | ----------------------------------------------------------------------\n",
|
|
" | Static methods defined here:\n",
|
|
" | \n",
|
|
" | __new__(*args, **kwargs) from builtins.type\n",
|
|
" | Create and return a new object. See help(type) for accurate signature.\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"help(map)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"id": "04106e30-95df-432a-b6b0-40fcc58f51e5",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"called add_two 1\n",
|
|
"called add_two 2\n",
|
|
"called add_two 3\n",
|
|
"[3, 4, 5]\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"x = list(map(add_two, [1, 2, 3]))\n",
|
|
"print(x)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "fba295ed-9dcb-4cbb-8b7e-3b0ff2965639",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"A!\n",
|
|
"B?\n",
|
|
"C.\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# commonly used with lambdas\n",
|
|
"for x in map(lambda x, y: x+y, (\"A\", \"B\", \"C\"), [\"!\", \"?\", \".\"]):\n",
|
|
" print(x)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"id": "18f5223a-b85a-44c6-9f49-40183a1e3208",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"A!!\n",
|
|
"B???\n",
|
|
"C....\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"# number of parameters must match number of iterables\n",
|
|
"for x in map(lambda x, y, z: x+(y*z), (\"A\", \"B\", \"C\"), [\"!\", \"?\", \".\"], [2, 3, 4]):\n",
|
|
" print(x)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"id": "c4e1d7f9-c111-44ff-8525-de147f90aa56",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"15"
|
|
]
|
|
},
|
|
"execution_count": 12,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"# operator module contains all of the common operators in function form\n",
|
|
"import operator\n",
|
|
"operator.sub(20, 5)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 14,
|
|
"id": "e6383ce1-6e06-44a4-beb2-1e946b81c483",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"{10}"
|
|
]
|
|
},
|
|
"execution_count": 14,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"set(map(operator.sub, [20, 19], [10, 9]))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 17,
|
|
"id": "b58441e4-ba95-43e4-8151-dd25e1c7efd1",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"('AAA', 'BBB', 'CCC')"
|
|
]
|
|
},
|
|
"execution_count": 17,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"# the result of `map` is a new kind of iterable (in fact a generator, which we'll cover next)\n",
|
|
"\n",
|
|
"# possible to pass into set or list \n",
|
|
"# or use anywhere you can use an iterable\n",
|
|
"tuple(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": 21,
|
|
"id": "62cac0ce-56e4-4ca7-9223-ed9be407428a",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"['ABC', 'XYZ']"
|
|
]
|
|
},
|
|
"execution_count": 21,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"list(filter(lambda s: s.isupper(), [\"a\", \"ABC\", \"AbCdeF\", \"XYZ\", \"\"]))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 22,
|
|
"id": "7eaab05d-2b8e-45fa-ad97-565c2edac0f6",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"['ABCABC', 'XYZXYZ']"
|
|
]
|
|
},
|
|
"execution_count": 22,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"list(map(lambda s: s*2, filter(str.isupper, [\"a\", \"ABC\", \"AbCdeF\", \"XYZ\"])))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 23,
|
|
"id": "c4a69097-c30c-4096-b69b-f3fa89a1bc7f",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"['A']"
|
|
]
|
|
},
|
|
"execution_count": 23,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"list(filter(str.isupper, map(lambda s: s.title(), [\"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": 24,
|
|
"id": "a623edc8-08cb-41d0-8b2c-fd99619fed73",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"10"
|
|
]
|
|
},
|
|
"execution_count": 24,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"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": 27,
|
|
"id": "5081e0e6-424b-472b-b0b0-f0c2bfa1344e",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"14"
|
|
]
|
|
},
|
|
"execution_count": 27,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"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 accumulator, new_val: accumulator + len(new_val), \n",
|
|
" names, \n",
|
|
" 0)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 30,
|
|
"id": "6fd2afda-b07f-45f6-9a82-6bc50665af6c",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"48"
|
|
]
|
|
},
|
|
"execution_count": 30,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"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], 2)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "74e7a581-3f79-4be3-ba9d-f354b1df13a1",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"functools.reduce(lambda a,b: a+b, [1, 2, 3])"
|
|
]
|
|
},
|
|
{
|
|
"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": 31,
|
|
"id": "5a23eb2c-8324-4ff1-beb2-bca7ff5dbbe1",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"20"
|
|
]
|
|
},
|
|
"execution_count": 31,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"import operator\n",
|
|
"operator.mul(2, 10)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 32,
|
|
"id": "70988dc5-1a32-4316-bb9a-d4be646dd2c2",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"-5"
|
|
]
|
|
},
|
|
"execution_count": 32,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"import functools\n",
|
|
"negate = functools.partial(operator.mul, -1)\n",
|
|
"negate(5)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 35,
|
|
"id": "995d61df-dfcf-411a-b371-7633ec9ed649",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"[-1, -2, -3, -4]"
|
|
]
|
|
},
|
|
"execution_count": 35,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"list(map(negate, [1, 2, 3, 4]))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 36,
|
|
"id": "7b2d87c2-903a-4b48-a012-3e3b0b03584f",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"16\n",
|
|
"16\n"
|
|
]
|
|
}
|
|
],
|
|
"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": 37,
|
|
"id": "0e2ffbc6-e05f-401e-b569-273c61f6d514",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"a!b!c\n",
|
|
"x!a!b!c\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"print_ex = functools.partial(print, sep=\"!\")\n",
|
|
"print_ex(\"a\", \"b\", \"c\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "6e9be6b5-0a68-4de6-8289-31fb5095d31f",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# parameters must be valid\n",
|
|
"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": [
|
|
"# another way to deal with functions we're calling with the same args repeatedly\n",
|
|
"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)"
|
|
]
|
|
},
|
|
{
|
|
"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": 40,
|
|
"id": "79029822-694a-445d-9776-48e05e94733b",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#f = lambda n: n ** 2\n",
|
|
"powers_of_two = [2**n for n in range(10)]\n",
|
|
"print(powers_of_two)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 41,
|
|
"id": "fe7d9640-165c-4887-a9f0-9e411fc8e031",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"['Q♠', 'Q♣', 'Q♦', 'Q♥', 'J♠', 'J♣', 'J♦', 'J♥']\n"
|
|
]
|
|
}
|
|
],
|
|
"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": 42,
|
|
"id": "24213ab6-3c6e-45df-8bb9-93b2d69c10fa",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"{8, 16, 2, 4}\n"
|
|
]
|
|
}
|
|
],
|
|
"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": 46,
|
|
"id": "95f3d657-39aa-4803-8fc7-4e736ebc5b20",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"{3: 2, 4: 3, 5: 4, 6: 5}\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"\n",
|
|
"powers_of_two_mapping = {n+2:n+1 for n in range(5) if n > 0}\n",
|
|
"print(powers_of_two_mapping)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 47,
|
|
"id": "7139c632-97cf-49a5-8abf-5b7516c1a401",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"<generator object <genexpr> at 0x1037de5e0>\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"p2gen = (2 ** n for n in [1,1,2,2,3,3,3,4,4,4])\n",
|
|
"print(p2gen)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "16f356d0-5147-455d-b7b4-385bd544c56a",
|
|
"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
|
|
}
|