{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Chapter 2 — An Array of Sequences\n", "\n", "**Sections with code snippets in this chapter:**\n", "\n", "* [List Comprehensions and Generator Expressions](#List-Comprehensions-and-Generator-Expressions)\n", "* [Slicing](#Slicing)\n", "* [Building Lists of Lists](#Building-Lists-of-Lists)\n", "* [Augmented Assignment with Sequences](#Augmented-Assignment-with-Sequences)\n", "* [list.sort and the sorted Built-In Function](#list.sort-and-the-sorted-Built-In-Function)\n", "* [Managing Ordered Sequences with bisect](#Managing-Ordered-Sequences-with-bisect)\n", "* [Arrays](#Arrays)\n", "* [Memory Views](#Memory-Views)\n", "* [NumPy and SciPy](#NumPy-and-SciPy)\n", "* [Deques and Other Queues](#Deques-and-Other-Queues)\n", "* [Soapbox](#Soapbox)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## List Comprehensions and Generator Expressions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-1. Build a list of Unicode codepoints from a string" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[36, 162, 163, 165, 8364, 164]" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "symbols = '$¢£¥€¤'\n", "codes = []\n", "\n", "for symbol in symbols:\n", " codes.append(ord(symbol))\n", "\n", "codes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-2. Build a list of Unicode codepoints from a string, take 2" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[36, 162, 163, 165, 8364, 164]" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "symbols = '$¢£¥€¤'\n", "\n", "codes = [ord(symbol) for symbol in symbols]\n", "\n", "codes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Box: Listcomps No Longer Leak Their Variables" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'ABC'" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = 'ABC'\n", "codes = [ord(x) for x in x]\n", "x" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[65, 66, 67]" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "codes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-3. The same list built by a listcomp and a map/filter composition" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[162, 163, 165, 8364, 164]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "symbols = '$¢£¥€¤'\n", "beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]\n", "beyond_ascii" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[162, 163, 165, 8364, 164]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))\n", "beyond_ascii" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-4. Cartesian product using a list comprehension" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('black', 'S'),\n", " ('black', 'M'),\n", " ('black', 'L'),\n", " ('white', 'S'),\n", " ('white', 'M'),\n", " ('white', 'L')]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "colors = ['black', 'white']\n", "sizes = ['S', 'M', 'L']\n", "tshirts = [(color, size) for color in colors for size in sizes]\n", "tshirts" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "('black', 'S')\n", "('black', 'M')\n", "('black', 'L')\n", "('white', 'S')\n", "('white', 'M')\n", "('white', 'L')\n" ] } ], "source": [ "for color in colors:\n", " for size in sizes:\n", " print((color, size))" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('black', 'S'),\n", " ('black', 'M'),\n", " ('black', 'L'),\n", " ('white', 'S'),\n", " ('white', 'M'),\n", " ('white', 'L')]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "shirts = [(color, size) for size in sizes\n", " for color in colors]\n", "tshirts" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-5. Initializing a tuple and an array from a generator expression" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(36, 162, 163, 165, 8364, 164)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "symbols = '$¢£¥€¤'\n", "tuple(ord(symbol) for symbol in symbols)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array('I', [36, 162, 163, 165, 8364, 164])" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import array\n", "array.array('I', (ord(symbol) for symbol in symbols))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-6. Cartesian product in a generator expression" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "black S\n", "black M\n", "black L\n", "white S\n", "white M\n", "white L\n" ] } ], "source": [ "colors = ['black', 'white']\n", "sizes = ['S', 'M', 'L']\n", "\n", "for tshirt in ('%s %s' % (c, s) for c in colors for s in sizes):\n", " print(tshirt)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Slicing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Why Slices and Range Exclude the Last Item" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[10, 20]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l = [10, 20, 30, 40, 50, 60]\n", "\n", "l[:2] # split at 2" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[30, 40, 50, 60]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l[2:]" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[10, 20, 30]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l[:3] # split at 3" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[40, 50, 60]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l[3:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Slice Objects" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'bye'" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = 'bicycle'\n", "s[::3]" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'elcycib'" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[::-1]" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'eccb'" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[::-2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-9. Line items from a flat-file invoice" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " $17.50 imoroni PiBrella \n", " $4.95 mm Tactile Switch x20 \n", " $28.00 anavise Jr. - PV-201 \n", " $34.95 iTFT Mini Kit 320x240 \n", " \n" ] } ], "source": [ "invoice = \"\"\"\n", "0.....6.................................40........52...55........\n", "1909 Pimoroni PiBrella $17.50 3 $52.50\n", "1489 6mm Tactile Switch x20 $4.95 2 $9.90\n", "1510 Panavise Jr. - PV-201 $28.00 1 $28.00\n", "1601 PiTFT Mini Kit 320x240 $34.95 1 $34.95\n", "\"\"\"\n", "\n", "SKU = slice(0, 6)\n", "DESCRIPTION = slice(6, 40)\n", "UNIT_PRICE = slice(40, 52)\n", "QUANTITY = slice(52, 55)\n", "ITEM_TOTAL = slice(55, None)\n", "\n", "line_items = invoice.split('\\n')[2:]\n", "\n", "for item in line_items:\n", " print(item[UNIT_PRICE], item[DESCRIPTION])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Assigning to Slices" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l = list(range(10))\n", "l" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 20, 30, 5, 6, 7, 8, 9]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l[2:5] = [20, 30]\n", "l" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 20, 30, 5, 8, 9]" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "del l[5:7]\n", "l" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 20, 11, 5, 22, 9]" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l[3::2] = [11, 22]\n", "l" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By design, this example raises an exception::" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TypeError('can only assign an iterable')\n" ] } ], "source": [ "try:\n", " l[2:5] = 100\n", "except TypeError as e:\n", " print(repr(e))" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 100, 22, 9]" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l[2:5] = [100]\n", "l" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using + and * with Sequences" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l = [1, 2, 3]\n", "l * 5" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'abcdabcdabcdabcdabcd'" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "5 * 'abcd'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Building Lists of Lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-10. A list with three lists of length 3 can represent a tic-tac-toe board" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "board = [['_'] * 3 for i in range(3)]\n", "board" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "board[1][2] = 'X'\n", "board" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-11. A list with three references to the same list is useless" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "weird_board = [['_'] * 3] * 3\n", "weird_board" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', 'O'], ['_', '_', 'O'], ['_', '_', 'O']]" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "weird_board[1][2] = 'O'\n", "weird_board" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Explanation" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "board = []\n", "for i in range(3):\n", " row = ['_'] * 3\n", " board.append(row)\n", "board" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', '_'], ['_', '_', '_'], ['X', '_', '_']]" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "board[2][0] = 'X'\n", "board" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Augmented Assignment with Sequences" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [], "source": [ "l = [1, 2, 3]\n", "idl = id(l)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4414271936" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# NBVAL_IGNORE_OUTPUT\n", "idl" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 1, 2, 3]" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l *= 2\n", "l" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "id(l) == idl # same list" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [], "source": [ "t = (1, 2, 3)\n", "idt = id(t)" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4414275328" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# NBVAL_IGNORE_OUTPUT\n", "idt" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t *= 2\n", "id(t) == idt # new tuple" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A += Assignment Puzzler" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TypeError(\"'tuple' object does not support item assignment\")\n" ] } ], "source": [ "t = (1, 2, [30, 40])\n", "try:\n", " t[2] += [50, 60]\n", "except TypeError as e:\n", " print(repr(e))" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 2, [30, 40, 50, 60])" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-14. Bytecode for the expression s[a] += b" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 1 0 LOAD_NAME 0 (s)\n", " 2 LOAD_NAME 1 (a)\n", " 4 DUP_TOP_TWO\n", " 6 BINARY_SUBSCR\n", " 8 LOAD_NAME 2 (b)\n", " 10 INPLACE_ADD\n", " 12 ROT_THREE\n", " 14 STORE_SUBSCR\n", " 16 LOAD_CONST 0 (None)\n", " 18 RETURN_VALUE\n" ] } ], "source": [ "import dis\n", "\n", "dis.dis('s[a] += b')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## list.sort and the sorted Built-In Function" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['apple', 'banana', 'grape', 'raspberry']" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fruits = ['grape', 'raspberry', 'apple', 'banana']\n", "sorted(fruits)" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['grape', 'raspberry', 'apple', 'banana']" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fruits" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['raspberry', 'grape', 'banana', 'apple']" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sorted(fruits, reverse=True)" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['grape', 'apple', 'banana', 'raspberry']" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sorted(fruits, key=len)" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['raspberry', 'banana', 'grape', 'apple']" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sorted(fruits, key=len, reverse=True)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['grape', 'raspberry', 'apple', 'banana']" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fruits" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['apple', 'banana', 'grape', 'raspberry']" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fruits.sort()\n", "fruits" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Managing Ordered Sequences with bisect" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-15. bisect finds insertion points for items in a sorted sequence" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DEMO: bisect_right\n", "haystack -> 1 4 5 6 8 12 15 20 21 23 23 26 29 30\n", "31 @ 14 | | | | | | | | | | | | | |31\n", "30 @ 14 | | | | | | | | | | | | | |30\n", "29 @ 13 | | | | | | | | | | | | |29\n", "23 @ 11 | | | | | | | | | | |23\n", "22 @ 9 | | | | | | | | |22\n", "10 @ 5 | | | | |10\n", " 8 @ 5 | | | | |8 \n", " 5 @ 3 | | |5 \n", " 2 @ 1 |2 \n", " 1 @ 1 |1 \n", " 0 @ 0 0 \n" ] } ], "source": [ "# BEGIN BISECT_DEMO\n", "import bisect\n", "import sys\n", "\n", "HAYSTACK = [1, 4, 5, 6, 8, 12, 15, 20, 21, 23, 23, 26, 29, 30]\n", "NEEDLES = [0, 1, 2, 5, 8, 10, 22, 23, 29, 30, 31]\n", "\n", "ROW_FMT = '{0:2d} @ {1:2d} {2}{0:<2d}'\n", "\n", "def demo(haystack, needles, bisect_fn):\n", " print('DEMO:', bisect_fn.__name__) # <1>\n", " print('haystack ->', ' '.join('%2d' % n for n in haystack))\n", " for needle in reversed(needles):\n", " position = bisect_fn(haystack, needle) # <2>\n", " offset = position * ' |' # <3>\n", " print(ROW_FMT.format(needle, position, offset)) # <4>\n", "\n", "demo(HAYSTACK, NEEDLES, bisect.bisect) # <5>\n", "# END BISECT_DEMO" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "DEMO: bisect_left\n", "haystack -> 1 4 5 6 8 12 15 20 21 23 23 26 29 30\n", "31 @ 14 | | | | | | | | | | | | | |31\n", "30 @ 13 | | | | | | | | | | | | |30\n", "29 @ 12 | | | | | | | | | | | |29\n", "23 @ 9 | | | | | | | | |23\n", "22 @ 9 | | | | | | | | |22\n", "10 @ 5 | | | | |10\n", " 8 @ 4 | | | |8 \n", " 5 @ 2 | |5 \n", " 2 @ 1 |2 \n", " 1 @ 0 1 \n", " 0 @ 0 0 \n" ] } ], "source": [ "demo(HAYSTACK, NEEDLES, bisect.bisect_left)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-16. Given a test score, grade returns the corresponding letter grade" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['F', 'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A']" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):\n", " i = bisect.bisect(breakpoints, score)\n", " return grades[i]\n", "\n", "[grade(score) for score in [55, 60, 65, 70, 75, 80, 85, 90, 95]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-17. bisect_left maps a score of 60 to grade F, not D as in Example 2-16." ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['F', 'F', 'D', 'D', 'C', 'C', 'B', 'B', 'A']" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):\n", " i = bisect.bisect_left(breakpoints, score)\n", " return grades[i]\n", "\n", "[grade(score) for score in [55, 60, 65, 70, 75, 80, 85, 90, 95]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-18. Insort keeps a sorted sequence always sorted" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "insert 10 -> [10]\n", "insert 0 -> [0, 10]\n", "insert 6 -> [0, 6, 10]\n", "insert 8 -> [0, 6, 8, 10]\n", "insert 7 -> [0, 6, 7, 8, 10]\n", "insert 2 -> [0, 2, 6, 7, 8, 10]\n", "insert 10 -> [0, 2, 6, 7, 8, 10, 10]\n" ] } ], "source": [ "import bisect\n", "import random\n", "\n", "SIZE = 7\n", "\n", "random.seed(1729)\n", "\n", "my_list = []\n", "\n", "for i in range(SIZE):\n", " new_item = random.randrange(SIZE*2)\n", " bisect.insort(my_list, new_item)\n", " print(f'insert {new_item:2d} -> {my_list}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## When a List Is Not the Answer" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-19. Creating, saving, and loading a large array of floats" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.5963321947530882" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from array import array\n", "from random import random\n", "\n", "floats = array('d', (random() for i in range(10**7)))\n", "floats[-1]" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [], "source": [ "with open('floats.bin', 'wb') as fp:\n", " floats.tofile(fp)" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.5963321947530882" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "floats2 = array('d')\n", "\n", "with open('floats.bin', 'rb') as fp:\n", " floats2.fromfile(fp, 10**7)\n", "\n", "floats2[-1]" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "floats2 == floats" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Memory Views" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-20. Changing the value of an array item by poking one of its bytes" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numbers = array('h', [-2, -1, 0, 1, 2])\n", "memv = memoryview(numbers)\n", "len(memv)" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-2" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "memv[0]" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "memv_oct = memv.cast('B')\n", "memv_oct.tolist()" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array('h', [-2, -1, 1024, 1, 2])" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "memv_oct[5] = 4\n", "numbers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### NumPy and SciPy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-21. Basic operations with rows and columns in a numpy.ndarray" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "a = np.arange(12)\n", "a" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "numpy.ndarray" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(a)" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(12,)" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.shape" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3],\n", " [ 4, 5, 6, 7],\n", " [ 8, 9, 10, 11]])" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.shape = 3, 4\n", "a" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 8, 9, 10, 11])" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[2]" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[2, 1]" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 5, 9])" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[:, 1]" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 4, 8],\n", " [ 1, 5, 9],\n", " [ 2, 6, 10],\n", " [ 3, 7, 11]])" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.transpose()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-22. Loading, saving, and vectorized operations" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [], "source": [ "with open('floats-1M-lines.txt', 'wt') as fp:\n", " for _ in range(1_000_000):\n", " fp.write(f'{random()}\\n')" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [], "source": [ "floats = np.loadtxt('floats-1M-lines.txt')" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.29150425, 0.33893554, 0.08112756])" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "floats[-3:]" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.14575213, 0.16946777, 0.04056378])" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "floats *= .5\n", "floats[-3:]" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from time import perf_counter as pc\n", "\n", "t0 = pc()\n", "floats /= 3\n", "(pc() - t0) < 0.01" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [], "source": [ "np.save('floats-1M', floats)\n", "floats2 = np.load('floats-1M.npy', 'r+')\n", "floats2 *= 6" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "memmap([0.29150425, 0.33893554, 0.08112756])" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "floats2[-3:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Deques and Other Queues" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-22. Working with a deque" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import collections\n", "\n", "dq = collections.deque(range(10), maxlen=10)\n", "dq" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6])" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dq.rotate(3)\n", "dq" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dq.rotate(-4)\n", "dq" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dq.appendleft(-1)\n", "dq" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33])" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dq.extend([11, 22, 33])\n", "dq" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8])" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dq.extendleft([10, 20, 30, 40])\n", "dq" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Soapbox" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Mixed bag lists" ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [], "source": [ "l = [28, 14, '28', 5, '9', '1', 0, 6, '23', 19]" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TypeError(\"'<' not supported between instances of 'str' and 'int'\")\n" ] } ], "source": [ "try:\n", " sorted(l)\n", "except TypeError as e:\n", " print(repr(e))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Key is Brilliant" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, '1', 5, 6, '9', 14, 19, '23', 28, '28']" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l = [28, 14, '28', 5, '9', '1', 0, 6, '23', 19]\n", "\n", "sorted(l, key=int)" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, '1', 14, 19, '23', 28, '28', 5, 6, '9']" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sorted(l, key=str)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.0" } }, "nbformat": 4, "nbformat_minor": 2 }