{ "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", "* [Tuples Are Not Just Immutable Lists](#Tuples-Are-Not-Just-Immutable-Lists)\n", "* [Unpacking sequences and iterables](#Unpacking-sequences-and-iterables)\n", "* [Pattern Matching with Sequences](#Pattern-Matching-with-Sequences)\n", "* [Slicing](#Slicing)\n", "* [Using + and * with Sequences](#Using-+-and-*-with-Sequences)\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", "* [When a List Is Not the Answer](#When-a-List-Is-Not-the-Answer)\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": [ "| 概念 | 說明 | 範例 |\n", "| --------------- | ---------------------------------------------------- | ------------------------------------------------- |\n", "| **抽象基礎類別(ABC)** | 定義了一組方法名稱與結構的接口,類別只要實作這些方法,就會被視為符合該類別 | `abc.Sequence`, `abc.MutableSequence` 等 |\n", "| **虛擬子類別** | 雖然**沒有繼承** ABC,但只要**實作了對應的方法**,Python 就會視它為 ABC 的子類別 | `list` 雖然沒繼承 `MutableSequence`,但因為方法相符,就被視為其虛擬子類別 |\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**(超類別)** `Collection`/ `Reversible` <- `Sequence` <- `MutableSequence` **(子類別)**" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n", "True\n", "True\n" ] } ], "source": [ "from collections import abc\n", "\n", "print(issubclass(tuple, abc.Sequence))\n", "print(issubclass(tuple, abc.MutableSequence))\n", "print(issubclass(list, abc.Sequence))\n", "print(issubclass(list, abc.MutableSequence))\n" ] }, { "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": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[36, 162, 163, 165, 8364, 164]" ] }, "execution_count": 4, "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, using a listcomp" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[36, 162, 163, 165, 8364, 164]" ] }, "execution_count": 5, "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": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'ABC'" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = 'ABC'\n", "codes = [ord(x) for x in x]\n", "x" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[65, 66, 67]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "codes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`:=` 允許你在一個運算式中給變數賦值,且 scope 是封閉的函式 (enclosing function),所以在 listcomp 完成後還可以讀取。例如:\n", "```python\n", "if (n := len(data)) > 10:\n", " print(f\"Data is too long: {n}\")\n", "```\n", "這樣就不需要重複 `len(data)` 兩次。" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "67" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "codes = [last := ord(c) for c in x]\n", "last" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "inside demo: 6\n", "global total: 0\n" ] } ], "source": [ "def demo(data, total):\n", " _ = [total := total + v for v in data]\n", " print(\"inside demo:\", total)\n", "\n", "total = 0\n", "demo([1,2,3], 0)\n", "print(\"global total:\", total)" ] }, { "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": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[162, 163, 165, 8364, 164]" ] }, "execution_count": 3, "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": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[162, 163, 165, 8364, 164]" ] }, "execution_count": 4, "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": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('black', 'S'),\n", " ('black', 'M'),\n", " ('black', 'L'),\n", " ('white', 'S'),\n", " ('white', 'M'),\n", " ('white', 'L')]" ] }, "execution_count": 5, "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": 6, "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": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('black', 'S'),\n", " ('white', 'S'),\n", " ('black', 'M'),\n", " ('white', 'M'),\n", " ('black', 'L'),\n", " ('white', 'L')]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tshirts = [(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": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(36, 162, 163, 165, 8364, 164)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "symbols = '$¢£¥€¤'\n", "tuple(ord(symbol) for symbol in symbols)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array('I', [36, 162, 163, 165, 8364, 164])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import array\n", "\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": 1, "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": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "## Tuples Are Not Just Immutable Lists" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "#### Example 2-7. Tuples used as records" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`tuple` 只能接一個引數,並且**可以排序**" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TypeError: tuple expected at most 1 argument, got 2\n", "AttributeError: 'tuple' object has no attribute 'sort'\n", "[-118.408056, 33.9425]\n" ] } ], "source": [ "try:\n", " lax_coordinates = tuple(33.9425, -118.408056)\n", "except TypeError: \n", " print(\"TypeError: tuple expected at most 1 argument, got 2\")\n", "\n", "lax_coordinates = tuple((33.9425, -118.408056))\n", "try:\n", " lax_coordinates.sort()\n", "except AttributeError:\n", " print(\"AttributeError: 'tuple' object has no attribute 'sort'\")\n", "print(sorted(lax_coordinates))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "BRA/CE342567\n", "ESP/XDA205856\n", "USA/31195855\n" ] } ], "source": [ "lax_coordinates = (33.9425, -118.408056)\n", "print(type(lax_coordinates))\n", "\n", "city, year, pop, chg, area = ('Tokyo', 2003, 32_450, 0.66, 8014)\n", "traveler_ids = [('USA', '31195855'), ('BRA', 'CE342567'), ('ESP', 'XDA205856')]\n", "\n", "for passport in sorted(traveler_ids):\n", " print('%s/%s' % passport)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "USA\n", "BRA\n", "ESP\n" ] } ], "source": [ "for country, _ in traveler_ids:\n", " print(country)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "### Tuples as Immutable Lists" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = (10, 'alpha', [1, 2])\n", "b = (10, 'alpha', [1, 2])\n", "a == b" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b[-1].append(99)\n", "a == b" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "(10, 'alpha', [1, 2, 99])" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def fixed(o):\n", " try:\n", " hash(o)\n", " except TypeError:\n", " return False\n", " return True\n", "\n", "\n", "tf = (10, 'alpha', (1, 2)) # Contains no mutable items\n", "tm = (10, 'alpha', [1, 2]) # Contains a mutable item (list)\n", "fixed(tf)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fixed(tm)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`tuple` 可以相加串接" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(10, 'alpha', (1, 2), 10, 'alpha', [1, 2])" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf + tm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`tuple` **不能使用** `tuple.copy()`\n", "- `copy.copy()`(淺拷貝, shallow copy)\n", " - 只複製最外層的容器物件,裡面的巢狀物件(例如 list 裡的 list)只是參考(reference)。\n", " - 也就是說,內層的資料仍指向原本的記憶體位置,兩者共享。 \n", "- `copy.deepcopy()`(深拷貝, deep copy)\n", " - 遞迴地複製所有巢狀物件。\n", " - 原物件與拷貝物件完全獨立,改其中一個不會影響另一個。\n", "\n", "| 功能 | `copy.copy()`(淺拷貝) | `copy.deepcopy()`(深拷貝) |\n", "| -------- | ------------------ | ---------------------- |\n", "| 複製外層 | ✅ | ✅ |\n", "| 複製內層巢狀物件 | ❌(參照原物件) | ✅(新建物件) |\n", "| 速度與效能 | 較快 | 較慢(因為遞迴複製) |\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "'tuple' object has no attribute 'copy'\n", "tf_copy = (10, 'alpha', (1, 2))\n", "tf_deepcopy = (10, 'alpha', (1, 2))\n" ] } ], "source": [ "try:\n", " tf_copy = tf.copy()\n", "except AttributeError: \n", " print(\"'tuple' object has no attribute 'copy'\")\n", "\n", "from copy import copy, deepcopy\n", "\n", "tf_copy = copy(tf)\n", "print(f\"tf_copy = {tf_copy}\")\n", "tf_deepcopy = deepcopy(tf)\n", "print(f\"tf_deepcopy = {tf_deepcopy}\")" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "## Unpacking sequences and iterables" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "33.9425" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lax_coordinates = (33.9425, -118.408056)\n", "latitude, longitude = lax_coordinates # unpacking\n", "latitude" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "-118.408056" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "longitude" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "(2, 4)" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "divmod(20, 8)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "(2, 4)" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t = (20, 8)\n", "divmod(*t)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "(2, 4)" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "quotient, remainder = divmod(*t)\n", "quotient, remainder" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "'id_rsa.pub'" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import os\n", "\n", "_, filename = os.path.split('/home/luciano/.ssh/id_rsa.pub')\n", "filename" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "### Using * to grab excess items" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "(0, 1, [2, 3, 4])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a, b, *rest = range(5)\n", "a, b, rest" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "(0, 1, [2])" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a, b, *rest = range(3)\n", "a, b, rest" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "(0, 1, [])" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a, b, *rest = range(2)\n", "a, b, rest" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "(0, [1, 2], 3, 4)" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a, *body, c, d = range(5)\n", "a, body, c, d" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "([0, 1], 2, 3, 4)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "*head, b, c, d = range(5)\n", "head, b, c, d" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "### Unpacking with * in function calls and sequence literals" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "(1, 2, 3, 4, (5, 6))" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def fun(a, b, c, d, *rest):\n", " return a, b, c, d, rest\n", "\n", "\n", "fun(*[1, 2], 3, *range(4, 7))" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "(0, 1, 2, 3, 4)" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "*range(4), 4" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2, 3, 4]" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[*range(4), 4]" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "{0, 1, 2, 3, 4, 5, 6, 7}" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "{*range(4), 4, *(5, 6, 7)}" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "### Nested unpacking\n", "#### Example 2-8. Unpacking nested tuples to access the longitude\n", "\n", "[02-array-seq/metro_lat_lon.py](02-array-seq/metro_lat_lon.py)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "## Pattern Matching with Sequences\n", "#### Example 2-9. Method from an imaginary Robot class" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "# def handle_command(self, message):\n", "# match message:\n", "# case ['BEEPER', frequency, times]:\n", "# self.beep(times, frequency)\n", "# case ['NECK', angle]:\n", "# self.rotate_neck(angle)\n", "# case ['LED', ident, intensity]:\n", "# self.leds[ident].set_brightness(ident, intensity)\n", "# case ['LED', ident, red, green, blue]:\n", "# self.leds[ident].set_color(ident, red, green, blue)\n", "# case _:\n", "# raise InvalidCommand(message)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "#### Example 2-10. Destructuring nested tuples—requires Python ≥ 3.10.\n", "[02-array-seq/match_lat_lon.py](02-array-seq/match_lat_lon.py)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " | latitude | longitude\n", "Mexico City | 19.4333 | -99.1333\n", "New York-Newark | 40.8086 | -74.0204\n", "São Paulo | -23.5478 | -46.6358\n" ] } ], "source": [ "metro_areas = [\n", " ('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),\n", " ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),\n", " ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),\n", " ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),\n", " ('São Paulo', 'BR', 19.649, (-23.547778, -46.635833)),\n", "]\n", "\n", "def main():\n", " print(f'{\"\":15} | {\"latitude\":>9} | {\"longitude\":>9}')\n", " for record in metro_areas:\n", " match record:\n", " case [name, _, _, (lat, lon)] if lon <= 0:\n", " print(f'{name:15} | {lat:9.4f} | {lon:9.4f}')\n", "main()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "### Pattern Matching Sequences in an Interpreter\n", "#### Example 2-11. Matching patterns without match/case.\n", "[02-array-seq/lispy/py3.9/lis.py](02-array-seq/lispy/py3.9/lis.py)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "#### Example 2-12. Pattern matching with match/case—requires Python ≥ 3.10.\n", "[02-array-seq/lispy/py3.10/lis.py](02-array-seq/lispy/py3.10/lis.py)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Slicing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Why Slices and Range Exclude the Last Item" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[10, 20]" ] }, "execution_count": 38, "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": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[30, 40, 50, 60]" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l[2:]" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[10, 20, 30]" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l[:3] # split at 3" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[40, 50, 60]" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l[3:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Slice Objects" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'bye'" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = 'bicycle'\n", "s[::3]" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'elcycib'" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[::-1]" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'eccb'" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s[::-2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-13. Line items from a flat-file invoice" ] }, { "cell_type": "code", "execution_count": 45, "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": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l = list(range(10))\n", "l" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 20, 30, 5, 6, 7, 8, 9]" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l[2:5] = [20, 30]\n", "l" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 20, 30, 5, 8, 9]" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "del l[5:7]\n", "l" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 20, 11, 5, 22, 9]" ] }, "execution_count": 49, "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": 50, "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": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 100, 22, 9]" ] }, "execution_count": 51, "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": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l = [1, 2, 3]\n", "l * 5" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'abcdabcdabcdabcdabcd'" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "5 * 'abcd'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Building Lists of Lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-14. A list with three lists of length 3 can represent a tic-tac-toe board" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "board = [['_'] * 3 for i in range(3)]\n", "board" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "board[1][2] = 'X'\n", "board" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-15. A list with three references to the same list is useless" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "weird_board = [['_'] * 3] * 3\n", "weird_board" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', 'O'], ['_', '_', 'O'], ['_', '_', 'O']]" ] }, "execution_count": 57, "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": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]" ] }, "execution_count": 58, "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": 59, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['_', '_', '_'], ['_', '_', '_'], ['X', '_', '_']]" ] }, "execution_count": 59, "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": 60, "metadata": {}, "outputs": [], "source": [ "l = [1, 2, 3]\n", "idl = id(l)" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "140694277263808" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# NBVAL_IGNORE_OUTPUT\n", "idl" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 1, 2, 3]" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l *= 2\n", "l" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "id(l) == idl # same list" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [], "source": [ "t = (1, 2, 3)\n", "idt = id(t)" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "140694329335488" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# NBVAL_IGNORE_OUTPUT\n", "idt" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t *= 2\n", "id(t) == idt # new tuple" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A += Assignment Puzzler\n", "#### Example 2-16. A riddle" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "✅ `t[2] += [50, 60]` 的實際步驟: \n", "`+=` 是語法糖,其實它會被轉譯成兩個步驟: \n", "```python\n", "temp = t[2] # temp 指向 list [3, 4]\n", "temp = temp.__iadd__([50, 60]) # 等價於 temp.extend([50, 60])\n", "t[2] = temp # 嘗試把新的 list 回寫到 tuple 裡\n", "```\n", "❗ 錯誤出現在最後一步:\n", "`tuple` 是 **不可變的 (immutable)**,不能改變其元素,所以 `t[2] = temp` 報錯。\n", "\n", "但前面那一步:\n", "```python\n", "temp.__iadd__([50, 60])\n", "```\n", "已經就地修改了 `temp`(也就是 `t[2]`)的內容了!" ] }, { "cell_type": "code", "execution_count": 2, "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": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "#### Example 2-17. The unexpected result: item t2 is changed and an exception is raised" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 2, [30, 40, 50, 60])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-18. Bytecode for the expression s[a] += b" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0 RESUME 0\n", "\n", " 1 LOAD_NAME 0 (s)\n", " LOAD_NAME 1 (a)\n", " COPY 2\n", " COPY 2\n", " BINARY_OP 26 ([])\n", " LOAD_NAME 2 (b)\n", " BINARY_OP 13 (+=)\n", " SWAP 3\n", " SWAP 2\n", " STORE_SUBSCR\n", " LOAD_CONST 0 (None)\n", " 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": "markdown", "metadata": {}, "source": [ "> Fluent Interface \n", "\n", "代表你可以用「**鏈式方法呼叫**」,例如:\n", "\n", "```python\n", "s = \" hello \"\n", "result = s.strip().upper().replace(\"HELLO\", \"HI\")\n", "print(result) # HI\n", "```\n", "每個方法都回傳一個新的字串(不是 `None`),讓你可以一直串下去使用,這也是 receiver 的一種連續應用。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> Python 主排序演算法為 `Timsort`,屬於**穩定**演算法 \n", "\n", "代表排序時會**保留比較結果相同項目的相對順序** \n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['apple', 'banana', 'grape', 'raspberry']" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fruits = ['grape', 'raspberry', 'apple', 'banana']\n", "sorted(fruits)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['grape', 'raspberry', 'apple', 'banana']" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fruits" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['raspberry', 'grape', 'banana', 'apple']" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sorted(fruits, reverse=True)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['grape', 'apple', 'banana', 'raspberry']" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sorted(fruits, key=len)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['raspberry', 'banana', 'grape', 'apple']" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sorted(fruits, key=len, reverse=True)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['grape', 'raspberry', 'apple', 'banana']" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fruits" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['apple', 'banana', 'grape', 'raspberry']" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fruits.sort()\n", "fruits" ] }, { "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": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.8190492979077034" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from array import array\n", "from random import random, seed\n", "seed(10) # Use seed to make the output consistent\n", "\n", "floats = array('d', (random() for i in range(10 ** 7)))\n", "floats[-1]" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "with open('floats.bin', 'wb') as fp:\n", " floats.tofile(fp)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.8190492979077034" ] }, "execution_count": 10, "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": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "floats2 == floats" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Memory Views" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "#### Example 2-20. Handling 6 bytes memory of as 1×6, 2×3, and 3×2 views" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2, 3, 4, 5]" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "octets = array('B', range(6))\n", "m1 = memoryview(octets)\n", "m1.tolist()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "[[0, 1, 2], [3, 4, 5]]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m2 = m1.cast('B', [2, 3])\n", "m2.tolist()" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "[[0, 1], [2, 3], [4, 5]]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m3 = m1.cast('B', [3, 2])\n", "m3.tolist()" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "array('B', [0, 1, 2, 33, 22, 5])" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m2[1,1] = 22\n", "m3[1,1] = 33\n", "octets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-21. Changing the value of an 16-bit integer array item by poking one of its bytes" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 16, "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": 86, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-2" ] }, "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ "memv[0]" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]" ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "memv_oct = memv.cast('B')\n", "memv_oct.tolist()" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array('h', [-2, -1, 1024, 1, 2])" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "memv_oct[5] = 4\n", "numbers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### NumPy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-22. Basic operations with rows and columns in a numpy.ndarray" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "\n", "a = np.arange(12)\n", "a" ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "numpy.ndarray" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(a)" ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(12,)" ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.shape" ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3],\n", " [ 4, 5, 6, 7],\n", " [ 8, 9, 10, 11]])" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.shape = 3, 4\n", "a" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 8, 9, 10, 11])" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[2]" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[2, 1]" ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 5, 9])" ] }, "execution_count": 95, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[:, 1]" ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 4, 8],\n", " [ 1, 5, 9],\n", " [ 2, 6, 10],\n", " [ 3, 7, 11]])" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.transpose()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-22. Loading, saving, and vectorized operations" ] }, { "cell_type": "code", "execution_count": 97, "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": 98, "metadata": {}, "outputs": [], "source": [ "floats = np.loadtxt('floats-1M-lines.txt')" ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.06078257, 0.61741189, 0.84349987])" ] }, "execution_count": 99, "metadata": {}, "output_type": "execute_result" } ], "source": [ "floats[-3:]" ] }, { "cell_type": "code", "execution_count": 100, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.03039128, 0.30870594, 0.42174994])" ] }, "execution_count": 100, "metadata": {}, "output_type": "execute_result" } ], "source": [ "floats *= .5\n", "floats[-3:]" ] }, { "cell_type": "code", "execution_count": 101, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 101, "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": 102, "metadata": {}, "outputs": [], "source": [ "np.save('floats-1M', floats)\n", "floats2 = np.load('floats-1M.npy', 'r+')\n", "floats2 *= 6" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "memmap([0.06078257, 0.61741189, 0.84349987])" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "floats2[-3:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Deques and Other Queues" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 2-23. Working with a deque" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 104, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import collections\n", "\n", "dq = collections.deque(range(10), maxlen=10)\n", "dq" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6])" ] }, "execution_count": 105, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dq.rotate(3)\n", "dq" ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])" ] }, "execution_count": 106, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dq.rotate(-4)\n", "dq" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] }, "execution_count": 107, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dq.appendleft(-1)\n", "dq" ] }, { "cell_type": "code", "execution_count": 108, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33])" ] }, "execution_count": 108, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dq.extend([11, 22, 33])\n", "dq" ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8])" ] }, "execution_count": 109, "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": 110, "metadata": {}, "outputs": [], "source": [ "l = [28, 14, '28', 5, '9', '1', 0, 6, '23', 19]" ] }, { "cell_type": "code", "execution_count": 111, "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": 112, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, '1', 5, 6, '9', 14, 19, '23', 28, '28']" ] }, "execution_count": 112, "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": 113, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, '1', 14, 19, '23', 28, '28', 5, 6, '9']" ] }, "execution_count": 113, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sorted(l, key=str)" ] }, { "cell_type": "code", "execution_count": 113, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "existing-proj (3.14.0)", "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.14.0rc1" } }, "nbformat": 4, "nbformat_minor": 2 }