diff --git a/01-data-model/data-model.ipynb b/01-data-model/data-model.ipynb index 81f4c20..a9cdadb 100644 --- a/01-data-model/data-model.ipynb +++ b/01-data-model/data-model.ipynb @@ -6,7 +6,7 @@ "source": [ "# Chapter 1 — The Python Data Model\n", "\n", - "**Sections with examples:**\n", + "**Sections code snippets in this chapter:**\n", "\n", "* [A Pythonic Card Deck](#A-Pythonic-Card-Deck)\n", "* [Emulating Numeric Types](#Emulating-Numeric-Types)" @@ -23,7 +23,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Example 1-1. A deck as a sequence of playing cards" + "#### Example 1-1. A deck as a sequence of playing cards" ] }, { @@ -140,7 +140,7 @@ { "data": { "text/plain": [ - "Card(rank='2', suit='hearts')" + "Card(rank='Q', suit='clubs')" ] }, "execution_count": 6, @@ -463,7 +463,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Example 1-2. A simple two-dimensional vector class" + "#### Example 1-2. A simple two-dimensional vector class" ] }, { diff --git a/02-array-seq/.gitignore b/02-array-seq/.gitignore new file mode 100644 index 0000000..ab5fce6 --- /dev/null +++ b/02-array-seq/.gitignore @@ -0,0 +1,3 @@ +floats-*.txt +floats-*.npy +floats.bin diff --git a/02-array-seq/array-seq.ipynb b/02-array-seq/array-seq.ipynb new file mode 100644 index 0000000..f8782fe --- /dev/null +++ b/02-array-seq/array-seq.ipynb @@ -0,0 +1,2203 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Chapter 2 — An Array of Sequences\n", + "\n", + "**Sections 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::\n", + "\n", + "```python\n", + ">>> l[2:5] = 100\n", + "Traceback (most recent call last):\n", + " ...\n", + "TypeError: can only assign an iterable\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0, 1, 100, 22, 9]" + ] + }, + "execution_count": 25, + "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": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "l = [1, 2, 3]\n", + "l * 5" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'abcdabcdabcdabcdabcd'" + ] + }, + "execution_count": 27, + "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": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "board = [['_'] * 3 for i in range(3)]\n", + "board" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]" + ] + }, + "execution_count": 29, + "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": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weird_board = [['_'] * 3] * 3\n", + "weird_board" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[['_', '_', 'O'], ['_', '_', 'O'], ['_', '_', 'O']]" + ] + }, + "execution_count": 31, + "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": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" + ] + }, + "execution_count": 32, + "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": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[['_', '_', '_'], ['_', '_', '_'], ['X', '_', '_']]" + ] + }, + "execution_count": 33, + "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": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "140413155609544" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "l = [1, 2, 3]\n", + "id(l)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 1, 2, 3]" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "l *= 2\n", + "l" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "140413155609544" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "id(l) # same list" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "140413154489904" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t = (1, 2, 3)\n", + "id(t)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "140413265327592" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t *= 2\n", + "id(t) # new tuple" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### A += Assignment Puzzler" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "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": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1, 2, [30, 40, 50, 60])" + ] + }, + "execution_count": 40, + "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": 41, + "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": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['apple', 'banana', 'grape', 'raspberry']" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fruits = ['grape', 'raspberry', 'apple', 'banana']\n", + "sorted(fruits)" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['grape', 'raspberry', 'apple', 'banana']" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fruits" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['raspberry', 'grape', 'banana', 'apple']" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted(fruits, reverse=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['grape', 'apple', 'banana', 'raspberry']" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted(fruits, key=len)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['raspberry', 'banana', 'grape', 'apple']" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted(fruits, key=len, reverse=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['grape', 'raspberry', 'apple', 'banana']" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fruits" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['apple', 'banana', 'grape', 'raspberry']" + ] + }, + "execution_count": 48, + "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": 49, + "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__) # <5>\n", + " print('haystack ->', ' '.join('%2d' % n for n in haystack))\n", + " for needle in reversed(needles):\n", + " position = bisect_fn(haystack, needle) # <1>\n", + " offset = position * ' |' # <2>\n", + " print(ROW_FMT.format(needle, position, offset)) # <3>\n", + "\n", + "demo(HAYSTACK, NEEDLES, bisect.bisect)\n", + "# END BISECT_DEMO" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "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": 51, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['F', 'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A']" + ] + }, + "execution_count": 51, + "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": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['F', 'F', 'D', 'D', 'C', 'C', 'B', 'B', 'A']" + ] + }, + "execution_count": 52, + "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": 53, + "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": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.5963321947530882" + ] + }, + "execution_count": 54, + "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": 55, + "metadata": {}, + "outputs": [], + "source": [ + "with open('floats.bin', 'wb') as fp:\n", + " floats.tofile(fp)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.5963321947530882" + ] + }, + "execution_count": 56, + "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": 57, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 57, + "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": 58, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 58, + "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": 59, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "-2" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "memv[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "memv_oct = memv.cast('B')\n", + "memv_oct.tolist()" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array('h', [-2, -1, 1024, 1, 2])" + ] + }, + "execution_count": 61, + "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": 62, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "a = np.arange(12)\n", + "a" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "numpy.ndarray" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(12,)" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0, 1, 2, 3],\n", + " [ 4, 5, 6, 7],\n", + " [ 8, 9, 10, 11]])" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a.shape = 3, 4\n", + "a" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 8, 9, 10, 11])" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a[2]" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a[2, 1]" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1, 5, 9])" + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a[:, 1]" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0, 4, 8],\n", + " [ 1, 5, 9],\n", + " [ 2, 6, 10],\n", + " [ 3, 7, 11]])" + ] + }, + "execution_count": 69, + "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": 70, + "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": 71, + "metadata": {}, + "outputs": [], + "source": [ + "floats = np.loadtxt('floats-1M-lines.txt')" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.29150425, 0.33893554, 0.08112756])" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "floats[-3:]" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.14575213, 0.16946777, 0.04056378])" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "floats *= .5\n", + "floats[-3:]" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0065746790060075" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from time import perf_counter as pc\n", + "\n", + "t0 = pc(); floats /= 3; pc() - t0" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [], + "source": [ + "np.save('floats-1M', floats)\n", + "floats2 = np.load('floats-1M.npy', 'r+')\n", + "floats2 *= 6" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "memmap([0.29150425, 0.33893554, 0.08112756])" + ] + }, + "execution_count": 76, + "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": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import collections\n", + "\n", + "dq = collections.deque(range(10), maxlen=10)\n", + "dq" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6])" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dq.rotate(3)\n", + "dq" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dq.rotate(-4)\n", + "dq" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9])" + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dq.appendleft(-1)\n", + "dq" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33])" + ] + }, + "execution_count": 81, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dq.extend([11, 22, 33])\n", + "dq" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8])" + ] + }, + "execution_count": 82, + "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": 83, + "metadata": {}, + "outputs": [], + "source": [ + "l = [28, 14, '28', 5, '9', '1', 0, 6, '23', 19]" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "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": 85, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0, '1', 5, 6, '9', 14, 19, '23', 28, '28']" + ] + }, + "execution_count": 85, + "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": 86, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0, '1', 14, 19, '23', 28, '28', 5, 6, '9']" + ] + }, + "execution_count": 86, + "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.7.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/02-array-seq/slice-assign.rst b/02-array-seq/slice-assign.rst new file mode 100644 index 0000000..2d5f681 --- /dev/null +++ b/02-array-seq/slice-assign.rst @@ -0,0 +1,11 @@ +Assigning to Slices +=================== + +An example that raises an error:: + +>>> l = list(range(10)) +>>> l[2:5] = 100 +Traceback (most recent call last): + ... +TypeError: can only assign an iterable +