{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 序列\n",
    "\n",
    "`序列` \n",
    ":   每个元素可以是任何类型（也可以是序列），每个元素被分配一个序号（从 `0` 开始）。序号，也叫索引，表示元素的位置。\n",
    "\n",
    "Python 中的常用序列有：元组，列表，字符串，字节串，{class}`range` 对象等。\n",
    "\n",
    "```{admonition} 元组和列表的本质区别\n",
    "列表是可以修改的而元组则不能。\n",
    "```\n",
    "\n",
    "## 序列的基本操作\n",
    "\n",
    "以元组为例。\n",
    "\n",
    "### 索引\n",
    "\n",
    "索引，类似于获取数学中集合的元素的操作：返回序列中的元素。\n",
    "\n",
    "```{code-block}\n",
    "序列[索引编号]\n",
    "```\n",
    "\n",
    "示例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = (1, 2, 3, 4)\n",
    "a[0] # 获取列表 a 的第一个元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[-2] # 获取列表 a 的倒数第二个元素"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 切片\n",
    "\n",
    "切片，类似获取数学中集合的子集的操作。返回子序列。\n",
    "\n",
    "使用方法：\n",
    "\n",
    "```{code-block}\n",
    "序列[开始编号:结束编号后一个:步长]\n",
    "```\n",
    "\n",
    "`步长` 若为 `1`，可以省略："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2, 3)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = (1, 2, 3, 4, 5)\n",
    "a[1:3] # 获取 a 的子列表 [a[1], a[2]]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2, 3, 4)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[1:-1] # 获取 a 除去首尾元素的组成的子列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2, 3, 4, 5)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[1:] # 获取 a 除去首元素的组成的子列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 2, 3, 4)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[:-1] # 获取 a 除去末尾元素的组成的子列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1, 2, 3, 4, 5)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[:] # 获取 a 的一个副本（浅拷贝）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 序列 `+`\n",
    "\n",
    "序列 `+` 用于同类型的序列的拼接：\n",
    "\n",
    "```{code-block}\n",
    "序列 + 序列\n",
    "```\n",
    "类似于\n",
    "\n",
    "```{code-block}\n",
    "一篮苹果 + 一篮香蕉 = 两篮水果\n",
    "```\n",
    "\n",
    "使用 Python 表示："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('苹果1', '苹果2', '香蕉1', '香蕉2', '香蕉3')"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "一篮苹果 = ('苹果1', '苹果2')\n",
    "一篮香蕉 = ('香蕉1', '香蕉2', '香蕉3')\n",
    "\n",
    "两篮水果 = 一篮苹果 + 一篮香蕉\n",
    "两篮水果"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`+`  不会改变原有的序列："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('苹果1', '苹果2')"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "一篮苹果 # 查看有没有改变"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 序列 `*`\n",
    "\n",
    "序列 `*` 使用方法：\n",
    "\n",
    "```{code-block}\n",
    "序列 * n\n",
    "```\n",
    "\n",
    "表示将序列的元素按照原有顺序重复 `n` 次。 \n",
    "\n",
    "类似于：\n",
    "\n",
    "```{code-block}\n",
    "一箱苹果 * n = n 箱苹果\n",
    "```\n",
    "\n",
    "Python 写作："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "一箱苹果 = ('苹果1', '苹果2')\n",
    "两箱苹果 = 一箱苹果 * 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```{note}\n",
    "这个比喻并不恰当，因为，不可能存在两箱完全相同的苹果。这个例子仅仅是为了说明序列乘法的，大家不用考虑细节。\n",
    "```\n",
    "\n",
    "### `index` 方法\n",
    "\n",
    "返回某个元素的索引，如若此元素不存在，则会引发异常。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [1, 2, 3, 45, 5, 45, 7, 84]\n",
    "a.index(45)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `in`\n",
    "\n",
    "`in`，类似于判断某个元素是否属于某个集合，并返回判断结果。\n",
    "\n",
    "使用方法：\n",
    "\n",
    "```{code-block}\n",
    "a in 序列A\n",
    "```\n",
    "\n",
    "若 $a\\in A$，则返回逻辑真值 {data}`True`，否则返回逻辑假值 {data}`False`。\n",
    "\n",
    "### 序列的长度，最大值，最小值\n",
    "\n",
    "`len`、`max`、`min` 分别返回序列的长度，最大值，最小值。使用方法：\n",
    "\n",
    "```{code-block}\n",
    "len(序列)\n",
    "max(序列)\n",
    "min(序列)\n",
    "```\n",
    "\n",
    "## 可变序列\n",
    "\n",
    "借由赋值语句可以对可变序列进行修改。\n",
    "\n",
    "下面仍然以列表 `a` 为例。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [1, 2, 3, 4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[2, 2, 3, 4]"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[0] = 2 # 修改 `a` 的首位元素\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[2, 5, 6, 4]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[1:3] = [5, 6] # 修改 `a` 的第 2、3 元素，即修改 `a` 的子集\n",
    "a "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[2, 4]"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[1:3] = '' # 删除 `a` 的第 2、3 元素\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[99, 88, 2, 4]"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[0:0] = [99, 88] # 在 `a` 的首位插入新的元素\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[99, 'h', 'e', 'l', 'l', 'o', 4]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[1:3] = list('hello') # 替换 `a` 的第 2、3 元素\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "del a[0] # 显式删除 `a` 的首位元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['h', 'e', 'l', 'l', 'o', 4]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a # 查看此时 a 的值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['l', 'o', 4]"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "del a[:3] # 显式删除 `a` 的前 3 项\n",
    "a "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 列表方法\n",
    "\n",
    "调用对象的方法：\n",
    "\n",
    "```{code-block}\n",
    "对象.方法(参数)\n",
    "```\n",
    "\n",
    "### `append` 方法\n",
    "\n",
    "`list.append(x)` ~ `a[len(a):] = [x]`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 4]"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [1, 2, 3]\n",
    "# 可以在列表的末尾追加新的元素\n",
    "a.append(4)\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 4, [1, 5, 'fr']]"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 列表的末尾追加新的元素可以是其他对象，包括列表\n",
    "a.append([1, 5, 'fr'])\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `count` 方法\n",
    "     \n",
    "查看某个元素在列表中出现的次数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [1, 2, 3, 4, 1, 2]\n",
    "a.count(1) # 计算 `1` 在 `a` 中出现的次数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `extend` 方法\n",
    "\n",
    "`list.extend(iterable)` ~ `a[len(a):] = iterable`\n",
    "\n",
    "使用其他列表拓展原有列表，其他列表的元素被添加到原有列表的末尾：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 4, 5, 6]"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [1, 2, 3]\n",
    "a.extend([4, 5, 6])\n",
    "a\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `insert` 方法\n",
    "\n",
    "在指定位置插入元素。第一个参数是插入元素的索引，因此，`a.insert(0, x)` 在列表开头插入元素， `a.insert(len(a), x)` 等同于 `a.append(x)`。\n",
    "\n",
    "在序列的某个位置插入一个元素："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 'hello', 3, 4]"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [1, 2, 3, 4]\n",
    "a.insert(2, 'hello')\n",
    "a\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 'hello', 3, 4, 'world']"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.insert(20, 'world')  # 20 号位置不存在，直接插到列表末尾\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `pop` 方法\n",
    "\n",
    "移除列表某个位置的元素并返回该元素，如若没有指定要移除元素的位置，则默认移除末项。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [1, 2, 3, 4]\n",
    "last = a.pop()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3]"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a # 最后的元素被移除"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[2, 3]"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "first = a.pop(0) # 移除首位元素\n",
    "a "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `remove` 方法\n",
    "\n",
    "移除序列中第一个与参数匹配的元素："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 4, 88, 2]"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [1, 2, 88, 3, 4, 88, 2]\n",
    "a.remove(88)\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `reverse` 方法\n",
    "\n",
    "将列表改为倒序："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[3, 5, 2, 4, 3, 2, 1]"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [1, 2, 3, 4, 2, 5, 3]\n",
    "a.reverse()\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `sort` 方法\n",
    "\n",
    "默认为升序："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 4, 6, 6, 7, 9]"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [4, 6, 2, 1, 7, 9, 6]\n",
    "a.sort()\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`sort` 可以传入参数：\n",
    "\n",
    "- `key` 用来为每个元素提取比较值（默认值为 `None`）；\n",
    "- `reverse` 为 `True` 时是反序（默认值为 `False`）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Judy', 'Perter', 'Perkins']"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "names = ['Judy', 'Perter', 'Perkins']\n",
    "names.sort(key=len)\n",
    "names"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 不可变变序列\n",
    "\n",
    "**不可变变序列** 是指元组的每个元素指向的引用永远不变。\n",
    "\n",
    "下面以元组为例说明。\n",
    "\n",
    "```{note}\n",
    "输出时，元组都要由圆括号标注，这样才能正确地解释嵌套元组。输入时，圆括号可有可无，不过经常是必须的（如果元组是更大的表达式的一部分）。不允许为元组中的单个元素赋值，当然，可以创建含列表等可变对象的元组。\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('python', '20150101', ['a', 'b'])"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = ('python', '20150101', ['a', 'b'])\n",
    "b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果修改 `b` 的元素，则会触发异常："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'tuple' object doesn't support item deletion",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_12744/12326120.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mdel\u001b[0m \u001b[0mb\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: 'tuple' object doesn't support item deletion"
     ]
    }
   ],
   "source": [
    "del b[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "但是元组内的元素则不受此限制："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('python', '20150101', ['a', 'b', 'd'])"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b2 = b[2] # 取出 `b` 的第 3 个元素\n",
    "b2.append('d') # 修改 b2\n",
    "b # 可以看到 b 的第 3 个元素被修改了，这是因为 b2 是可变的"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造 0 个或 1 个元素的元组比较特殊：为了适应这种情况，对句法有一些额外的改变。用一对空圆括号就可以创建空元组；只有一个元素的元组可以通过在这个元素后添加逗号来构建（圆括号里只有一个值的话不够明确）。丑陋，但是有效。例如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((), 0, ('hello',), 1)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "empty = ()\n",
    "singleton = 'hello',    # 注意结尾的逗号\n",
    "empty, len(empty), singleton, len(singleton)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 元组打包和序列解包\n",
    "\n",
    "语句 `t = 12345, 54321, 'hello!'` 是 **元组打包** 的例子：值 `12345`、 `54321` 和 `'hello!'` 一起被打包进元组。逆操作也可以：\n",
    "\n",
    "```python\n",
    "x, y, z = t\n",
    "```\n",
    "\n",
    "称之为 **序列解包**。适用于右侧的任何序列。序列解包时，左侧变量与右侧序列元素的数量应相等。\n",
    "\n",
    "```{hint}\n",
    "多重赋值其实只是元组打包和序列解包的组合。\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 推导式\n",
    "\n",
    "元组和列表支持推导式。\n",
    "\n",
    "## 序列解包\n",
    "\n"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "681b3f0bf9b1b90d6d0c88f7c199d2184ced41189915c665b64d57703d01fa88"
  },
  "kernelspec": {
   "display_name": "Python 3.9.7 64-bit ('hs': conda)",
   "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.9.7"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
