{"id":18656538,"url":"https://github.com/uinika/python-quick-guide","last_synced_at":"2025-11-05T21:30:21.359Z","repository":{"id":115220359,"uuid":"147472843","full_name":"uinika/python-quick-guide","owner":"uinika","description":"Python Quick Guide","archived":false,"fork":false,"pushed_at":"2019-01-18T14:45:05.000Z","size":178,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-12-27T14:44:32.570Z","etag":null,"topics":["pip","python3","virtualenv"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uinika.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-05T06:48:23.000Z","updated_at":"2024-12-06T17:02:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"ca7ad1f0-2cc4-4a43-93a1-ed09aee24d90","html_url":"https://github.com/uinika/python-quick-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uinika%2Fpython-quick-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uinika%2Fpython-quick-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uinika%2Fpython-quick-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uinika%2Fpython-quick-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uinika","download_url":"https://codeload.github.com/uinika/python-quick-guide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239471924,"owners_count":19644406,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pip","python3","virtualenv"],"created_at":"2024-11-07T07:23:55.142Z","updated_at":"2025-11-05T21:30:21.302Z","avatar_url":"https://github.com/uinika.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"---\ntitle: 言简意赅のPython3\ntags: Server\ncategories: Web\n---\n\nPython 诞生于 20 世纪 90 年代初，由荷兰人 Guido van Rossum 开发完成，是一款非常简洁易读的解释型脚本语言；擅长于科学计算与图形处理，传统的计算机视觉库[OpenCV](https://opencv.org/)、三维可视化库[VTK](https://www.vtk.org/)、医学图像处理库[ITK](https://itk.org/)都提供了 Python 调用接口，Python 也原生提供了[NumPy](http://www.numpy.org/)、[SciPy](https://www.scipy.org/)、[matplotlib](https://matplotlib.org/)等强大的科学计算扩展库。Web 开发方面，Python 也提供有[Django](https://www.Djangoproject.com/)、[Tornado](http://www.tornadoweb.org/en/stable/)两款常用的 Web 开发框架。总而言之，得益于强大的开源社区支持，Python 已经成为一门功能丰富的胶水语言。\n\n![](python/logo.png)\n\n本文的示例代码基于目前最新的[Python 3.6.6](https://www.python.org/downloads/)版本，在简单介绍相关语法，以及[pip](https://pypi.org/project/pip/)、[virtualenv](https://virtualenv.pypa.io/en/stable/)等扩展库的使用之后，将会最终完成一个基于 Django 的在线图片相似度比较程序。本文涉及的代码和 Markdown 都已经上传至笔者的[Github](https://github.com/uinika/python-quick-guide)，需要的朋友可以直接进行克隆，如果有任何建议或发现缪误请提交 issue。\n\n\u003c!-- more --\u003e\n\n## Hello World\n\nPython 运行环境安装非常方便，Windows 操作系统下直接前往[Python 官网](https://python.org)下载安装包（_注意添加环境变量_），使用 Debian 软件包格式的 Linux 操作系统可以通过如下命令安装：\n\n```bash\n➜  sudo apt install python3\n```\n\n笔者的 Linux 开发环境下，同时存在`Python 3.6.6`和`Python 2.7.15`两个版本，因此在 Z-Shell 命令行中运行`Hello World`程序时，需要显式输入`python3`，以指定操作系统打开`Python 3.6.6`运行环境。\n\n```bash\n➜  / python3\nPython 3.6.6 (default, Apr  1 2018, 05:46:30)\n[GCC 7.3.0] on linux\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n\u003e\u003e\u003e print(\"Hello World!\")\nHello World!\n```\n\n\u003e 代码执行完毕后，可以通过按下`CTRL + D`或者输入`exit()`退出 Python 运行环境。\n\n当然，也可以单独将`print(\"Hello World!\")`保存到一个独立的`test.py`代码文件，然后在命令行当中直接开始运行。\n\n```bash\n➜  1-hello-world python3 test1.py\nHello World!\n```\n\n默认情况下，Python 源代码是以`UTF-8`格式进行编码的，但可以通过向源文件头部添加如下声明来指定编码格式。\n\n```py\n# -*- coding: utf-8 -*-\n```\n\n可以在`.py`脚本文件的头部手动添加 Python 解释器的路径，从而在 Linux 系统可以方便的通过`./test1.py`执行该脚本，避免`python3 test1.py`写法的繁琐。\n\n```\n#!/usr/bin/python3\n```\n\nPython 使用缩进来表示代码块，相同代码块的语句必须包含相同的缩进空格数。\n\n```py\n# -*- coding: utf-8 -*-\nnumber = 2018\nif number \u003e 2020:\n    print(number)\nprint(number)\n```\n\n代码将只会执行最后的`print`语句，运行结果如下：\n\n```bash\n➜  1-hello-world git:(master) ✗ python3 test2.py\n2018\n```\n\n## 变量\n\nPython 是弱类型语言，因此声明变量时不需要指定数据类型，现在修改上一步的例子，声明一个`infomation`变量然后输出：\n\n```py\ninfomation = \"Hello World!\"\nprint(infomation)\n```\n\n执行结果如下：\n\n```bash\n➜  python3 test1.py\nHello World!\n```\n\n相对 C、Go、Java 等强类型语言，Python 的语法结构更为松散，但是变量的命名依然需要遵循以下规则：\n\n1. 变量名只能包含字母、数字、下划线，但不能以数字开头，例如`infomation_1`是合法的变量声明，但是`1_infomation`则属于非法。\n2. 变量名不能包含空格，不过可以使用下划线来分隔单词，例如`print_something`是合法的，但是`print something`属于非法。\n3. 不能使用 Python 关键字、函数名称作为变量名，例如`lambda`、`yield`、`raise`、`def`、`nonlocal`、`elif`、`assert`、`except`、`pass`、`with`。\n4. 建议使用小写字母作为变量名，并且谨慎使用小写字母`l`和大写字母`O`，因为两者很容易被代码阅读者混淆为数字`1`和`0`。\n5. 变量命名尽量见文知意，避免过度的缩写，例如`person_name`明显比`person_n`更加易读。\n\n熟悉了变量命名规则之后，进一步扩展上面的程序，对变量`infomation`重新进行赋值然后打印输出：\n\n```py\ninfomation = \"Hello World!\"\nprint(infomation)\n\ninfomation = \"Hello Hank!\"\nprint(infomation)\n```\n\n执行后将会输出两次打印结果：\n\n```bash\n➜  python3 test2.py\nHello World!\nHello Hank!\n```\n\n**traceback**（_回溯,追踪_）是 Python 语法解析器提供给开发人员的代码错误提示信息，可以更加直观的定位错误发生的代码位置。\n\n```bash\n➜  python test3.py\nTraceback (most recent call last):  File \"test3.py\", line 2, in \u003cmodule\u003e\n    print(deom)NameError: name 'deom' is not defined\n```\n\n## 注释\n\npython 当中可以使用`#`声明一个**单行注释**。\n\n```py\n# Comment\nprint(\"使用井号的单行注释；\")\n```\n\n或者使用`3`个单引号`'''`声明一个**多行注释**。\n\n```py\n'''\nFirst Comment\nSecond Comment\n'''\nprint(\"使用3个单引号声明的多行注释；\")\n```\n\n也可以使用`3`个双引号`\"\"\"`声明一个**多行注释**。\n\n```py\n\"\"\"\nFirst Comment\nSecond Comment\n\"\"\"\nprint(\"使用3个双引号声明的多行注释；\")\n```\n\n## 数据类型\n\nPython 是弱类型语言，使用前不需要专门声明，赋值之后变量即被创建。Python 一共拥有 5 种标准的数据类型：**数值**（_Number_）、**字符串**（_String_）、**列表**（_List_）、**元组**（_Tuple_）、**字典**（_Dictionary_）。Python 这 5 种标准数据类型除了通过字面量方式声明之外，还可以通过构造函数`int()`、`float()`、`complex()`、`str()`、`list()`、`tuple()`、`dict()`进行声明。\n\nPython 当中除了这五种标准数据类型之外，还存在**二进制序列类型**（`bytes`, `bytearray`, `memoryview`）、**集合类型**（`set`, `frozenset`）等衍生的数据类型，本文这里并不将其作为基本数据类型进行介绍，开发人员可以结合官方文档的[《Internal Objects》](https://docs.python.org/3.6/library/stdtypes.html#internal-objects)章节按需进行查阅。\n\n### 数值 Number\n\n由于 Python 非常适合于科学计算用途，因此对于数值类型方面内容的讲解篇幅相对较大。Python 的数值类型分为**整型**（_精度不限_）、**浮点类型**（_底层使用 C 语言的双精度浮点类型实现_）、**复数类型**（_包含实部和虚部_）三种，其中**布尔类型**是作为整型的子类型出现。\n\n当前硬件设备对 Python 浮点数精度的相关支持信息，可以通过如下代码进行查看。\n\n```py\nimport sys\nprint(sys.float_info)\n```\n\n上述代码在笔者的 64 位 Linux 系统上执行的结果如下：\n\n```py\nsys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)\n```\n\n全部数值类型都支持的运算符：\n\n| 操作     | 结果                      | 示例                   |\n| :------- | :------------------------ | :--------------------- |\n| `x + y`  | `x`与`y`的和              | `3 + 2`，结果为`5`。   |\n| `x - y`  | `x`与`y`的差              | `5 - 1`，结果为`4`。   |\n| `x * y`  | `x`与`y`的乘积            | `3 * 9`，结果为`27`。  |\n| `x ** y` | `x`的`y`幂次方            | `2 ** 3`，结果为`8`。  |\n| `x / y`  | `x`和`y`的商              | `8 / 2`，结果为`4.0`。 |\n| `x // y` | `x`和`y`的商取整          | `4 // 3`，结果为`1`。  |\n| `x % y`  | `x`与`y`的余数            | `12 % 7`，结果为`5`。  |\n| `-x`     | 取`x`的负数               | `-3`。                 |\n| `+x`     | 取`x`的正数，原值不会变化 | `+3`。                 |\n\n全部数值类型都支持的方法：\n\n| 操作              | 结果                                              | 示例                                                      |\n| :---------------- | :------------------------------------------------ | :-------------------------------------------------------- |\n| `abs(x)`          | 取`x`的绝对值                                     | `abs(-32.3)`，结果为`32.3`。                              |\n| `int(x)`          | 取`x`的整型                                       | `int(3.84)`，结果为`3`。                                  |\n| `float(x)`        | 取`x`的浮点类型                                   | `float(5)`，结果为`5.0`。                                 |\n| `complex(re, im)` | 一个以`re`作为实部`im`（默认为`0`）作为虚部的实数 | `complex(2.02, 3.3)`，结果为`(2.02+3.3j)`。               |\n| `c.conjugate()`   | 复数`c`的共轭复数                                 | `(complex(2.02, 3.3)).conjugate()`，结果为`(2.02-3.3j)`。 |\n| `divmod(x, y)`    | 由`(x // y, x % y)`组成的值对                     | `divmod(12, 7)`，结果为`(1, 5)`。                         |\n| `pow(x, y)`       | `x`的`y`幂次方，等效于`x ** y`                    | `pow(2, 3)`，结果为`8`。                                  |\n\n整型的位操作：\n\n| 操作     | 结果     | 示例                   |\n| :------- | :------- | :--------------------- |\n| `x \u0026 y`  | 按位与   | `3 \u0026 2`，结果为`2`。   |\n| `x ｜ y` | 按位或   | `3 ｜ 2`，结果为`3`。  |\n| `x ^ y`  | 按位异或 | `3 ^ 2`，结果为`1`。   |\n| `x \u003c\u003c n` | 左移位   | `3 \u003c\u003c 2`，结果为`12`。 |\n| `x \u003e\u003e n` | 右移位   | `3 \u003e\u003e 2`，结果为`0`。  |\n| `~x`     | 按位取反 | `~3`，结果为`-4`。     |\n\nPython 的 Boolean 值由`False`和`True`两个静态对象组成，其它对象参与布尔运算时，通常被认为是`True`（_除非重写其类定义当中的`__bool__()`方法并返回`False`，或者重写`__len__()`并返回`0`_），下列对象在布尔运算中会被认为是`False`。\n\n1. 被定义为`False`的等效常量：`None`、`False`。\n2. 任意值为`0`的数值类型：`0`、`0.0`、`0j`、`Decimal(0)`、`Fraction(0, 1)`。\n3. 空的序列或者集合：`''`、`()`、`[]`、`{}`、`set()`、`range(0)`。\n\n\u003e 包含布尔结果的 Python 内建函数总是返回`0`和`False`或者`1`和`True`。\n\n特别需要注意的是：**布尔运算`or`和`and`总是返回其中一个操作数本身**，请参见下面的布尔运算符说明表：\n\n| 操作      | 结果                                         | 示例                    |\n| :-------- | :------------------------------------------- | :---------------------- |\n| `x or y`  | 如果`x`为假，那么返回`y`，否则返回`x`        | `2 or 3`，结果为`3`。   |\n| `x and y` | 如果`x`为假，那么返回`x`, 否则返回`y`        | `2 and 3`，结果为`2`。  |\n| `not x`   | 如果`x`为假, 那么返回`True`, 否则返回`False` | `not 0`，结果为`True`。 |\n\nPython 拥有 6 个比较运算符，其各自的运算优先级相同，可以随意链式使用。例如：`x \u003c y \u003c= z`与`x \u003c y and y \u003c= z`等效。\n\n| 操作符       | 结果                               | 示例                                         |\n| :----------- | :--------------------------------- | :------------------------------------------- |\n| `x \u003c y`      | 严格小于                           | `3 \u003c 1`，结果为`False`。                     |\n| `x \u003c= y`     | 小于或等于                         | `4 \u003c= 4`，结果为`True`。                     |\n| `x \u003e y`      | 严格大于                           | `12 \u003e 33`，结果为`False`。                   |\n| `x \u003e= y`     | 大于或等于                         | `21 \u003e= 19`，结果为`True`。                   |\n| `x == y`     | 等于                               | `[\"A\", \"B\"] == [\"A\", \"B\"]`，结果为`True`。   |\n| `x != y`     | 不等于                             | `21 != 21`，结果为`False`。                  |\n| `x is y`     | 对象引用地址的相等性判断           | `[\"A\", \"B\"] is [\"A\", \"B\"]`结果为`False`。    |\n| `x is not y` | 对象引用地址的相等性判断的结果取反 | `[\"A\", \"B\"] is not [\"A\", \"B\"]`结果为`True`。 |\n\n### 字符串 String\n\nPython 中的字符串是一个不可变的 Unicode 字符序列，可以保存在`str`对象或者字符串字面量当中。其中，字符串字面量可以通过如下 3 种方式书写：\n\n单引号：`'allows embedded \"double\" quotes'`。\n双引号：`\"allows embedded 'single' quotes\"`。\n三引号：`'''Three single quotes'''`、`\"\"\"Three double quotes\"\"\"`。\n\n\u003e 三引号字符串可以书写到多行，并且所有的空格都将会完整的保存下来。\n\nPython 字符串同样可以通过`class str(object=b'', encoding='utf-8', errors='strict')`构造器进行创建。\n\n```py\nstr(\"hello python!\") == \"hello python!\" # True\n```\n\nPython 字符串可以进行索引，字符串第 1 个字符的索引为`0`，子字符串可以使用分割符`:`来指定。\n\n```py\nhank = \"uinika\"\nprint(hank[0]) # 输出字符串'u'\nprint(hank[0:4])  # 输出字符串 'uini'\n```\n\n### 列表 List\n\n列表 List 是一个可变的序列（_即可以对列表的每个数据项进行修改_），用于存储同类数据的集合，可以通过如下方式进行创建：\n\n1. 使用方括号`[]`表达一个空的列表，例如`[]`；\n2. 使用方括号`[]`并且使用逗号`,`分隔每项数据，例如：`[1, 2, 3]`；\n3. 使用列表理解，例如`[x for x in iterable]`；\n4. 使用`list()`或者`list(iterable)`构造器；\n\n```py\n'''定义列表'''\ncars = ['FORD', 'HONDA', 'BMW']\n\nprint(cars) # 输出['FORD', 'HONDA', 'BMW']\n\n'''修改列表'''\ncar[2] = 'BENZ';\nprint(cars) # 输出['FORD', 'HONDA', 'BENZ']\n\n'''打印列表指定项'''\nprint(cars[1]) # 输出HONDA\n\n'''在列表尾部添加新的项目'''\ncars.append(\"BENTLEY\")\nprint(cars) # 输出['FORD', 'HONDA', 'BENZ', 'BENTLEY']\n\n'''返回一个列表的拷贝'''\nprint(cars[:]) # 输出['FORD', 'HONDA', 'BENZ', 'BENTLEY']\n\n'''指定位置批量插入值'''\ncars[1:2] = ['CHERY', 'BYD']\nprint(cars) # 输出['FORD', 'CHERY', 'BYD', 'BENZ', 'BENTLEY']\n\n'''打印列表长度'''\nprint(len(cars)) # 输出5\n\n'''清除列表'''\ncars = []\nprint(cars) # 输出[]\n```\n\n可以使用`class range(stop)`或者`class range(start, stop[, step])`生成一系列数值，通常指定`for`循环的次数。\n\n```py\nfor value in range(1, 5):\n  print(value)\n'''\n1\n2\n3\n4\n'''\n```\n\n使用`list()`构造函数可以将`range()`生成的结果直接转换为列表。\n\n```py\n\"\"\"生成range\"\"\"\nrange_numbers = range(1, 6)\nprint(type(range_numbers)) # \u003cclass 'range'\u003e\n\n\"\"\"转换为list\"\"\"\nlist_numbers = list(range_numbers)\nprint(type(list_numbers)) # \u003cclass 'list'\u003e\nprint(list_numbers) # [1, 2, 3, 4, 5]\n```\n\n### 元组 Tuple\n\n元组（_[ˈtʌpəl]_）是不可修改的序列类型，即不能对其中的元素进行修改。\n\n1. 使用圆括号`()`表达一个空的元组，例如`()`；\n2. 向只拥有一个数据项的元组最后添加逗号，例如：`(1,)`\n3. 使用逗号分隔不同的数据项，例如：`(1, 2, 3)`；\n4. 使用列表理解，例如`[x for x in iterable]`；\n5. 使用内建的`tuple()`或者`tuple(iterable)`构造函数；\n\n```py\n'''定义元组'''\ncompanies = (\"Google\", \"Facebook\", \"Microsoft\")\n\n'''访问元祖元素'''\nprint(\"Top 1 is\", companies[0]) # Top 1 is Google\n\n'''访问倒数第1个元祖元素'''\nprint(\"Countdown 1 is\", companies[-1]) # Countdown 1 is Microsoft\n\n'''截取元组前两个元素'''\nprint(\"Top 2 is\", companies[0: 2]) # Top 2 is ('Google', 'Facebook')\n\n'''拷贝元组'''\nprint(\"All companies is\", companies[0:]) # print(\"All companies are\", companies[0:])\n\n'''获取元组元素的个数'''\nprint(\"Number of companies is\", len(companies)) # Number of companies is 3\n\n'''修改元祖是非法的'''\ncompanies[1] = \"Yahoo\" # TypeError: 'tuple' object does not support item assignment\n\n'''删除元祖中的元素也是非法的'''\ndel companies[1] # TypeError: 'tuple' object doesn't support item deletion\n\n'''但是可以删除元组及其所属的变量，so，互联网泡沫来了...'''\ndel companies;\nprint(\"Oops, Internet bubble burst!\", companies) # NameError: name 'companies' is not defined\n```\n\n元组都可以使用`+`和`*`进行运算，也可以组合或者复制，然后获得一个新的元组。\n\n```py\n(1, 2, 3, \"A\", \"B\") + (4, 5, 6, \"C\", \"D\") # 输出(1, 2, 3, 'A', 'B', 4, 5, 6, 'C', 'D')\n\n(\"UFO,\")*5 # 输出'UFO,UFO,UFO,UFO,UFO,'\n\n\"Media\" in (\"System\", \"Softawre\", \"Media\") # 输出True\n\nfor index in (0,1,2,3,4,5): print(index);\n\"\"\"\n输出\n0\n1\n2\n3\n4\n5\n\"\"\"\n```\n\n\u003e 上面介绍的列表 List，也可以进行类似操作。\n\n### 字典 Dictionary\n\nPython 官方文档当中，将**列表**（_List_）和**元组**（_Tuple_）归纳为**序列类型**（_Sequence Types_），而将**字典**（_ dict_）类型归为**映射类型**（_Mapping Types_）。Python 中的字典类型是使用花括号`{}`包裹并通过逗号`,`分隔的`key-value`键值对，例如：`{\"name\": \"hank\", \"age\": 33}`。当然，同样也可以通过`class dict(**kwarg)`、`class dict(mapping, **kwarg)`、`class dict(iterable, **kwarg)`构造函数进行创建。\n\n```py\n'''定义字典'''\nhank = { \"name\": \"uinika\", 33: 1985 }\n\n'''访问字典'''\nprint(hank[\"name\"], hank[33]) # uinika 1985\n\n'''修改字典'''\nhank[33]=2018\nprint(hank) # {'name': 'uinika', 33: 2018}\n\n'''删除字典'''\ndel hank[33]\nprint(hank) # {'name': 'uinika'}\n\n'''使用len()打印字典长度'''\nprint(len(hank)) # 1\n\n'''使用str()输出字典字符串'''\nstring_hank = str(hank)\nprint(string_hank) # {'name': 'uinika'}\n\n'''使用str()输出字典字符串'''\nprint(type(string_hank)) # \u003cclass 'str'\u003e\n```\n\n字典的`key`值必须是不可变的，因此可以使用**数字**、**字符串**、**元组**作为键值。但是由于**列表**的元素是可变的，因此被不能作为字典的键值。\n\n```py\n'''打印一个使用元组作为key的字典元素'''\ndictionary = {(1, 2, 3):('A', 'B', 'C'), \"贰\": \"二\", \"叁\": \"三\"}\ndictionary[(1, 2, 3)] # ('A', 'B', 'C')\n```\n\n## 条件判断\n\nPython 的条件判断语句与其它类 C 语言相似，但是每个 condition 后面需要使用冒号`:`表示后面是满足条件后执行的语句块。需要注意的是，**Python 语句块的划分是通过缩来完成的，相同缩进数量的语句构成一个语句块**。\n\n```py\nif condition1:\n  block1\nelif condition2:\n  block2\nelse:\n  block3\n```\n\n下面的代码是一个条件判断语句的例子，当`if`和`elif`判断的结果都为`False`时，最终打印`else`子句的结果。\n\n```py\nif False:\n  print(\"Current condition is IF\")\nelif False:\n  print(\"Current condition is ELIF\")\nelse:\n  print(\"Current condition is ELSE\")\n\n'''\nCurrent condition is ELSE\n'''\n```\n\n\u003e Python 当中没有`switch/case`语句。\n\n## 循环\n\n### while 循环\n\nPython 中使用`while`循环时，需要特别注意与其它类 C 语言语法的不同，即语句后的**标识符`:`**与**代码块缩进**。\n\n```py\nindex = 1\n\nwhile index \u003c= 100:\n  print(index)  # 输出1~100的序数\n  index+=1\n```\n\n\u003e 注意了，Python 是没有`do/while`循环的。\n\n可以通过设置条件表达为`True`实现无限循环，请看下面的例子：\n\n```py\nwhile True:\n  print(\"Thit is an infinite loop\")\n```\n\n如果`while`循环体当中只拥有一条语句，可以将其与`while`关键字书写在同一行，因此上面无限循环的示例也可以写成下面这样：\n\n```py\nwhile True: print(\"Thit is an infinite loop\")\n```\n\nPython 的`while`循环拥有一个与其它类 C 语言截然不同的用法，即使用`while/else`语句在条件判断为`False`时执行`else`语句块当中的内容。\n\n```py\nindex = 1\n\nwhile index \u003c= 100:\n  print(index)\n  index+=1\nelse:\n  print(\"超过100啦！\")\n```\n\n### for 循环\n\nPython 的`for`语句可以用来对**列表**、**元组**、**字典**、**字符串**进行遍历操作。\n\n```py\ncars = ['FORD', 'HONDA', 'BMW']\n\nfor car in cars:\n  print(\"输出结果：\", car)\n\n'''\n输出结果： FORD\n输出结果： HONDA\n输出结果： BMW\n'''\n\ncompanies = (\"Google\", \"Facebook\", \"Microsoft\")\n\nfor company in companies:\n  print(\"输出结果：\", company)\n\n'''\n输出结果： Google\n输出结果： Facebook\n输出结果： Microsoft\n'''\n\ndictionaries = { \"total\": 10000, \"limit\": 50 }\n\nfor key, value in dictionaries.items(): # 字典的items()方法返回该字典的每个键值对\n  print(\"输出key值：\", key)\n  print(\"输出value值：\", value)\n\n'''\n输出key值： total\n输出value值： 10000\n输出key值： limit\n输出value值： 50\n'''\n\ntext = \"Chengdu\"\n\nfor character in text:\n  print(\"输出结果：\", character)\n\n'''\n输出结果： C\n输出结果： h\n输出结果： e\n输出结果： n\n输出结果： g\n输出结果： d\n输出结果： u\n'''\n```\n\n`for`语句同样可以结合`else`一起使用，`for`循环完毕之后，就会执行`else`子句中的代码。\n\n```py\nstring = \"成都\"\n\nfor liter in string:\n  print(liter)\nelse:\n  print(\"赵雷\")\n\n'''\n成\n都\n赵雷\n'''\n```\n\n### break 与 continue\n\n在 Python 的循环语句当中，可以通过`break`强行跳出当前循环体。\n\n```py\nfor number in [0, 1, 2, 3, 4, 5]:\n  if number == 5:\n    break\n  print(number)\n\nprint(\"Game over!\")\n\n'''\n0\n1\n2\n3\n4\nGame over!\n'''\n```\n\n也可以通过`continue`直接略过本次循环。\n\n```py\nfor number in [0, 1, 2, 3, 4, 5]:\n  if number == 3:\n    print(\"Skip number 3!\")\n    continue\n  print(number)\n\n'''\n0\n1\n2\nSkip number 3!\n4\n5\n'''\n```\n\n### pass\n\n`pass`被执行的时候，并不进行任何操作，只起到一个语法占位符的作用。\n\n```py\ndef demo(arg): pass # 定义一个不进行任何操作的函数\n\nclass Demo: pass    # 定义一个没有任何方法的类\n```\n\n可以通过定义一个只有`pass`语句的类，来实现类似 C 语言结构体的功能。\n\n```py\nclass Engineer:\n    pass\n\nhank = Engineer()\n\nhank.name = \"uinika\"\nhank.age = \"18\"\n\nprint(hank.name + \" is just only \" + hank.age) # uinika is just only 18\n```\n\n## 函数\n\nPython 使用关键字`def`来定义函数，使用方式和声明规则与其它类 C 语言相似。\n\n```py\n'''定义函数'''\ndef demo(parameter):\n  print('this is a' + parameter + '!')\n  return 0\n\n'''调用函数\ndemo(\"function\")\n```\n\n同其它类 C 语言一样，Python 中的变量也可以分为局部变量（_定义在函数内部_）和全局变量（_定义在函数外部_）。\n\n```py\n'''定义函数'''\ntest = '全局变量'\ndef demo():\n    test = '局部变量'\n    print(test) # 局部变量\n\n'''调用函数'''\ndemo()\n```\n\n### 命名参数\n\n调用 Python 函数时，可以向其传递命名参数，指定该参数值由哪个函数参数进行接收，避免按照顺序接收所可能带来的潜在错误。\n\n```py\ndef function(parameter):\n  print(\"parameter\", parameter)\n\n'''传递命名参数'''\nfunction(parameter = 0) # parameter 0\n```\n\n### 默认参数\n\n定义 Python 函数的时候，对于缺省的参数可以赋予其一个默认值。\n\n```py\n'''\n定义函数的时候声明了parameter2的默认参数\n'''\ndef function(parameter1, parameter2 = 2):\n  print(\"执行结果：\")\n  print(\"parameter1\", parameter1)\n  print(\"parameter2\", parameter2)\n)\n\nfunction(parameter1 = 1)\n\n'''\n执行结果：\nparameter1： 1\nparameter2： 2\n'''\n```\n\n### 可变参数列表\n\n定义函数时，可以使用星号`*`作为前缀来声明一个可变参数列表，用来接收调用函数时传递的任意个数参数，这些参数会被包装至一个**元组**。\n\n```py\n# 在可变参数之前，可以放置任意数量的普通参数\ndef demo(parameter, *tuple):\n  print('Parameter is：', parameter)\n  print('Tuple is：', tuple)\n\ndemo('Hello Python!', 1, 2, 3, '四', '五')\n\n'''\nParameter is： Hello Python!\nTuple is： (1, 2, 3, '四', '五')\n```\n\n也可以使用`**`作为前缀来声明参数，此时这些参数会包装为一个**字典**。\n\n```py\ndef demo(parameter, **dictionary):\n  print(\"Parameter is\", parameter)\n  print(\"Dictionary is\", dictionary)\n\ndemo(\"Hello World!\", a=1, b=2, c=3)\n\n'''\nParameter is Hello World!\nDictionary is {'a': 1, 'b': 2, 'c': 3}\n'''\n```\n\n如果`*`号**单独**出现在函数参数当中，那么后续的参数则必须使用**命名参数**显式传入。\n\n```PY\ndef demo(parameter1, *, parameter2, parameter3):\n  print(\"Parameter1 is\", parameter1)\n  print(\"Parameter2 is\", parameter2);\n  print(\"Parameter3 is\", parameter3);\n\ndemo(1, parameter2 = 2, parameter3 = 3)\n\n'''\nParameter1 is 1\nParameter2 is 2\nParameter3 is 3\n'''\n\ndemo(A, B, parameter3 = C)\n\n'''\nTraceback (most recent call last):\n  File \"test1.py\", line 14, in \u003cmodule\u003e\n    demo(A, B, parameter3 = C)\nNameError: name 'A' is not defined\n'''\n```\n\n### lambda 函数\n\nPython 的 lambda 函数是只由一个 Python 表达式所组成的匿名的内联函数，其语法书写形式如下：\n\n```py\nlambda [parameters]: expression\n```\n\nlamdba 函数的语法只能包含一条语句，例如：\n\n```py\ndemo = lambda parameterA, parameterB: print(parameterA / parameterB)\n\ndemo(1985, 8)\n\n'''\n248.125\n'''\n```\n\n### return 语句\n\n`return`语句用于退出函数并返回函数的执行结果值，具体用法如下代码所示：\n\n```py\ndef demo(parameter1, parameter2):\n  return parameter1 + parameter2\n\nprint(demo(83, 2))\n```\n\n当 Python 中的`return`语句没有返回值时，则默认返回值为`None`。\n\n```py\ndef demo():\n  return\n\nprint(demo())\n\n'''\nNone\n'''\n```\n\n\u003e 不带参数值的`return`语句返回`None`。\n\n## 作用域\n\nPython 当中仅`module`模块、`class`类、`def`或`lambda`函数会引入新作用域，`if/elif/else`、`try/except`、`for/while`等代码块并不会引入新作用域，即这些语句当中定义的变量在其外部也能访问。\n\n```py\ndef function():\n  STRING = \"This is a String!\"\n\nprint(text)\n\n'''\nTraceback (most recent call last):\n  File \"test1.py\", line 4, in \u003cmodule\u003e\n    print(text)\nNameError: name 'text' is not defined\n'''\n\ndef function():\n  text = \"This is a String!\"\n  print(text)\n\nfunction()\n\n'''\nThis is a String!\n'''\n```\n\n### `global`关键字\n\n使用`global`关键字声明的标识符将会引用至**全局变量**，在局部作用域中对其进行的修改操作都将会保留下来，就如同操作真正的全局变量一样。\n\n```py\ntext = \"全局变量\"\n\ndef function():\n  global text\n  print(text) # 输出：\"全局变量\"\n  text = \"局部变量\"\n  print(text) # 输出：\"局部变量\"\n\nfunction()\n\nprint(text) # 输出：\"局部变量\"\n```\n\n### `nonlocal`关键字\n\n使用`nonlocal`关键字声明的标识符将会引用至当前作用域外层的变量，在当前作用域对其进行的修改操作都将会保留，如同在真正的操作该作用域外层的变量一样。\n\n```py\ndef outer():\n    text = \"外部变量\"\n\n    def inner():\n      nonlocal text\n      text = \"内部变量\"\n      print(text) # 输出：\"内部变量\"\n\n    inner()\n\n    print(text) # 输出：\"内部变量\"\n\nouter()\n```\n\n## 类与实例\n\nPython 使用`class`关键字创建一个**类**，然后直接调用类名即其初始化方法就可以创建这个类的**实例**。类进行实例化时，会自动调用该类的初始化方法`__init__(self)`（_作用类似于 Java 当中的构造函数_）。\n\n```py\n# Dog类\nclass Dog:\n  # 类属性\n  age = \"\"\n  # 初始化方法\n  def __init__(self, age):\n    self.age = age;\n  # 类方法\n  def run(self):\n    print(\"I'm running!\")\n\npet = Dog(\"1岁\") # 实例化Dog类，并显式向初始化函数__init__传递参数\n\nprint(pet.age)\n\npet.run()\n\n'''\n1岁\nI'm running!\n'''\n```\n\n\u003e 注意：类方法（_包括初始化方法_）中的`self`参数是不能省略的，该参数指向类的实例，而非类本身。当然，根据个人编码习惯，也可以将`self`置换为其它语言中更为常用的`this`进行命名。\n\n### 继承\n\nPython 做为面向对象的语言，自然是支持继承的。需要继承一个类，只需要在定义子类时传入父类的名称即可，同时为了保证子类和父类都能够正确的实例化，子类的初始化方法需要显示调用父类的初始化方法。\n\n```py\n# 定义Dog父类\nclass Dog:\n  age = \"\"\n\n  def __init__(self, age):\n    self.age = age;\n\n  def run(self):\n    print(self.age)\n\n\n# 定义Puppy子类，并传入Dog父类\nclass Puppy(Dog):\n  weight = \"\"\n\n  def __init__(self, weight):\n    Dog.__init__(self, \"1岁\") # 调用父类Dog的初始化方法\n    self.weight = weight;\n\n  def cute(self):\n    print(self.weight)\n\npet = Puppy(\"10斤\")\n\npet.run() # 调用父类Dog的方法\npet.cute() # 调用子类Puppy的方法\n\n'''\n1岁\n10斤\n'''\n```\n\n如同 Java 一样，Python 也是可以实现多重继承的。多重继承时，为了保证继承树能够正确的进行实例化，需要在子类的初始化方法`__init__`内显式的调用父类们的初始化方法，并将子类的`self`属性传递过去。\n\n```py\nclass A:\n  attribute = \"\";\n  def __init__(self):\n    print(\"A\")\n\nclass B:\n  def __init__(self):\n    print(\"B\")\n\nclass C(A, B):\n  def __init__(self):\n    A.__init__(self) # 在子类初始化方法内调用父类A的初始化方法\n    B.__init__(self) # 在子类初始化方法内调用父类B的初始化方法\n    print(\"C\")\n\ndemo = C()\n\n'''\nA\nB\nC\n'''\n```\n\n### 私有属性和方法\n\n在类中声明属性和方法时添加两条下划线`__`，就可以将这个属性和方法声明为**私有**的。私有属性和方法只能在类中通过`self.__private`进行访问，而不能在类实例化后进行访问。\n\n```py\nclass demo:\n  __attribute = \"私有属性\"\n\n  def __getAttribute(self):\n    print(self.__attribute + \"私有方法\")\n\ntest = demo()\ntest.__attribute # AttributeError: 'demo' object has no attribute '__attribute'\ntest.__getAttribute() # AttributeError: 'demo' object has no attribute '__getAttribute'\n```\n\n### 方法重写 override\n\n如果父类中定义的方法不能满足要求，那么可以考虑在子类中对父类的方法进行重写。\n\n```py\nclass Parent:\n  def method(self):\n    print(\"输出：Parent\")\n\nclass Child(Parent):\n  def __init__(self):\n    Parent.__init__(self)\n  def method(self):\n    print(\"输出：Child\")\n\nchildInstance = Child()\n\nchildInstance.method() # 输出：Child\n```\n\n当然，也可以通过`super()`函数显式调用被子类重写了的父类方法。对于上面的例子，可以使用如下语句调用父类的`method()`方法。\n\n```py\nsuper(Child, childInstance).method() # 输出：Parent\n```\n\n### 迭代器\n\n大家可能注意到许多容器对象能够使用`for`语句进行循环处理，就像下面代码这样：\n\n```py\nfor element in [1, 2, 3]:\n    print(element)\n\nfor element in (1, 2, 3):\n    print(element)\n\nfor key in {'one':1, 'two':2}:\n    print(key)\n\nfor char in \"123\":\n    print(char)\n\nfor line in open(\"file.txt\"):\n    print(line, end='')\n```\n\n这样的处理方法简单明了，实质上`for`语句调用容器对象上的`iter()`方法，该方法返回一个迭代器对象，这个迭代器对象当中定义了一个`__next__()`方法用于操作容器对象的元素，当没有更多可供迭代的元素时，该方法将会抛出一个`StopIteration`异常通知`for`语句终止循环操作。这里你可以通过`next()`内置函数去调用`__next__()`方法，参见下面的例子：\n\n```py\nstring = 'abc'\n\nstringIterator = iter(string)\nprint(stringIterator) # 输出\u003cstr_iterator object at 0x00000000023F8898\u003e\n\nprint(next(stringIterator)) # 输出a\nprint(next(stringIterator)) # 输出b\nprint(next(stringIterator)) # 输出c\nprint(next(stringIterator))\n\n'''\n输出\nTraceback (most recent call last):\n  File \"test.py\", line 9, in \u003cmodule\u003e\n    print(next(stringIterator))\nStopIteration\n'''\n```\n\n定义一个`iter()`方法，该方法用`next()`方法返回一个对象。如果该类定义了`next()`，那么`iter()`就可以返回`self`。\n\n```py\n# 迭代器，用于反向循环一个序列\nclass Reverse:\n  def __init__(self, data):\n    self.data = data # 初始化函数传入的待处理数据\n    self.index = len(data) # 待处理数据的长度\n\n  def __iter__(self):\n    return self # 返回对象实例本身\n\n  def __next__(self):\n    if self.index == 0:\n      raise StopIteration\n    self.index = self.index - 1\n    return self.data[self.index] # 从字符串尾部开始逐一返回字母\n\nreverseUinika = Reverse('Hank')\niter(reverseUinika) # 生成迭代器对象\n\nfor char in reverseUinika: # 循环打印\n  print(char)\n\n'''\nk\nn\na\nH\n'''\n```\n\n### 生成器\n\n生成器 Generator 是一个用于建立迭代器 iterators 的简单又强大的工具，其书写方式类似于函数，但是在返回数据的时候使用了`yield`语句。当生成器的`next()`每次被调用的时候，生成器会恢复到其离开的位置（_生成器能够记忆所有的数据和最后执行的语句位置_）。\n\n```py\ndef reverse(data):\n  for index in range(len(data) - 1, -1, -1):\n    yield data[index] # 使用yield语句\n\nfor char in reverse(\"Hank\"):\n  print(char)\n\n'''\nk\nn\na\nH\n'''\n```\n\n上述代码实现了之前迭代器示例相同的功能，生成器函数代码如此短小精悍的原因在于`iter()`和`next()`方法的创建以及`StopIteration`异常抛出都是自动进行的。另外生成器函数的局部变量和执行状态在每次调用都会被保存，这样比前面基于 class 的迭代器总是手动处理`self.index`和`self.data`更加便捷。\n\n一些简单的生成器可以使用特殊语法书（_与列表解析相似，不过使用圆括号代替了_）书写为一种更加简捷的表达式，即**生成器表达式**。这种表达式常用于在闭包函数内使用生成器的情况，语法上比完整的生成器定义更紧凑，并且比同等的列表理解更加容易记忆。\n\n```py\n# 求平方和\nsumOfSquares = sum(index * index for index in range(10))\nprint(sumOfSquares) # 285\n\n# 求点积\na = [10, 20, 30]\nb = [7, 5, 3]\ndotProduct = sum(x*y for x,y in zip(a, b))\nprint(dotProduct) # 260\n```\n\n## 异常处理\n\n与其它类 C 语言一样，Python 通过`try...except`语句块提供了健全的错误和异常处理机制。首先，`try`和`except`当中的子句被执行，此时如果没有异常出现，`except`子句会被跳过，同时`try`语句块正常执行完成。如果`try`的子句当中发生了异常，则会中断剩下子句的执行流程，并跳转去执行`except`关键字后声明异常类型所对应的语句，完成后继续执行该`try`语句块后续的内容。如果对应的异常类型没有找到，该异常会被传递到`try`语句块之外，如果语句块外依然没有进行相应的处理，那么程序的执行流程会被中断 ，并且向控制台打印出异常信息。\n\n```py\ntry:\n  number = 1 % 0\nexcept ZeroDivisionError as error:\n  print(error)  # integer division or modulo by zero\n```\n\n当然，也可以在一个`except`子句中捕捉多个异常。\n\n```py\nexcept (RuntimeError, TypeError, NameError):\n  pass\n```\n\n如果`except`子句中的**异常类**具有继承关系，则它们都将会被触发。\n\n```py\n# 继承Exception类\nclass ExceptionA(c):\n  pass\n\nclass ExceptionB(ExceptionA):\n  pass\n\nclass ExceptionC(ExceptionB):\n  pass\n\n# 循环A、B、C异常类并抛出异常\nfor exception in [ExceptionA, ExceptionB, ExceptionC]:\n  try:\n    raise exception() # 抛出异常\n  except ExceptionC:\n    print(\"ExceptionC\")\n  except ExceptionB:\n    print(\"ExceptionB\")\n  except ExceptionA:\n    print(\"ExceptionA\")\n\n'''\nExceptionA\nExceptionB\nExceptionC\n'''\n```\n\n\u003e 如果将上面代码中`except`子句的处理顺序颠倒一下，那么打印结果会变为`ExceptionA ExceptionB ExceptionC`，这是因为异常类 A、B、C 产生的异常全部都会被异常类 A 捕捉然后中断执行。\n\n值得注意的是，最后一条`except`子句可以省略掉异常名称，从而可以补捉到全部的异常类型，虽然同样可以执行打印错误信息和抛出异常的操作，不过要十分小心的使用，因为它可能会掩盖掉真实发生的异常信息。\n\n```py\ntry:\n    raise Exception\nexcept OSError:\n    print(\"OSError错误\")\nexcept:\n    print(\"匹配所有异常\")\n    raise\n\n'''\n匹配所有异常\nTraceback (most recent call last):\n  File \"test.py\", line 4, in \u003cmodule\u003e\n    raise Exception\nException\n'''\n```\n\n`try…except…`异常处理语句还拥有一个`else…`子句，用来在`try`子句没有捕捉到异常时执行一些必要的代码（_如果`try…except…`时发生了异常，则`else…`子句中的异常将不会得到执行_）。\n\n```py\ntry:\n    normal = 888\nexcept Exception:\n    print(\"捕获异常！\")\nelse:\n    print(\"没有异常发生时总是会被执行！\")  # 没有异常发生时总是会被执行！\n```\n\n可以在`raise`子句当中声明**异常的参数**，并在`except`当中通过`as`关键字进行实例化以后进行接收。\n\n```py\ntry:\n  raise Exception(\"This is an Exception!\")\nexcept Exception as exception:\n  print(type(exception))  # \u003cclass 'Exception'\u003e\n  print(exception.args)  # ('This is an Exception!',)\n  print(exception)  # This is an Exception!\n```\n\n\u003e 由于`Exception`类里定义了`__str__()`方法，所以可以通过直接打印异常对象来获取异常参数。\n\nPython 的异常处理机制，不光能处理`try`子句当中发生的异常，还能够处理`try`中调用的函数内发生的异常。\n\n```py\ndef division():\n  x = 1 / 0\n\ntry:\n  division()\nexcept ZeroDivisionError as error:\n  print(error)  # division by zero\n```\n\n`raise`子句当中所要抛出的异常类必须继承自`Exception`，当异常被触发的时候，该异常类会被自动实例化并将执行流程带入`except`子句。\n\n```py\nclass MyError(Exception):\n  def __init__(self):\n    Exception.__init__(self)\n    print(\"自定义异常类的构造方法被调用了！\")\n\ntry:\n  raise MyError # 等效于raise ValueError()\nexcept MyError:\n  print(MyError)\n\n'''\n自定义异常类的构造方法被调用了！\n\u003cclass '__main__.MyError'\u003e\n'''\n```\n\n如果希望不对抛出的异常进行处理，那么可以选择在`except`子句内重新将这个异常抛出。\n\n```py\ntry:\n    raise NameError(\"发生了一些错误!\")\nexcept NameError as error:\n    print(error)\n    raise\n\n'''\n发生了一些错误!\nTraceback (most recent call last):\n  File \"test1.py\", line 2, in \u003cmodule\u003e\n    raise NameError(\"发生了一些错误!\")\nNameError: 发生了一些错误!\n'''\n```\n\n开发人员可以自定义异常类，这些自定义的异常类必须继承自内置的`Exception`类。自定义异常类通常只会定义几个用来描述异常的属性，从而保持类定义的简单明了。对于一个模块发生多个错误，可以通过建立一个异常类的继承树来进行体现，来看下面的例子：\n\n```py\n# 针对该模块的自定义异常基类\nclass Error(Exception):\n    pass\n\n# 定义一个输入错误异常，继承了Error基类\nclass InputError(Error):\n  def __init__(self, expression, message):\n    self.expression = expression  # 异常的输入表达式\n    self.message = message  # 异常信息说明\n\n# 定义试图完成一个不被允许的状态转换操作时所发生的异常，继承了Error基类\nclass TransitionError(Error):\n  def __init__(self, previous, next, message):\n    self.previous = previous # 转换开始时的状态\n    self.next = next # 尝试建立一个新的状态\n    self.message = message # 解释为什么这个转换不被允许的原因\n```\n\n\u003e **Python 异常的命名通常会以`\"Error\"`结尾，建议自定义异常时保持这样的惯例**。\n\n`try`语句还拥有一个可以用来进行一些清除操作的`finally`子句，该子句无论不否发生异常都会被执行（_与 else 的最大不同点_），读者可以参考下面的例子：\n\n```py\ndef divide(x, y):\n    try:\n        result = x / y\n    except ZeroDivisionError:\n        print(\"不能使用0作为除数！\")\n    else:\n        print(\"除法的结果是：\", result)\n    finally:\n        print(\"结束子句！\")\n\ndivide(2, 1)\n'''\n除法的结果是： 2.0\n结束子句！\n'''\n\ndivide(2, 0)  # 不能使用0作为除数！ 结束子句！\n'''\n不能使用0作为除数！\n结束子句！\n'''\n\ndivide(\"2\", \"1\")\n'''\n结束子句！\nTraceback (most recent call last):\n  File \"test1.py\", line 13, in \u003cmodule\u003e\n    divide(\"2\", \"1\")\n  File \"test1.py\", line 3, in divide\n    result = x / y\nTypeError: unsupported operand type(s) for /: 'str' and 'str'\n'''\n```\n\n## 模块管理\n\nPython 通过`import`关键字来引入其它模块，并且需要将其放置到代码的顶部。Python 当中`.py`文件的名称就是模块的名称，模块的名称可以通过全局变量`__name__`进行访问（_如果该模块是 python 命令行直接执行的模块，则`__name__`属性的打印结果为`\"__main__\"`_）。\n\n```py\n# myModule.py\ndef test():\n    print(\"这是\" + __name__ + \"模块里的测试方法！\")\n```\n\n```py\n# main.py\nimport myModule\n\nmyModule.test()\n```\n\n```py\n# 打印结果\n这是myModule模块里的测试方法！\n```\n\n每个模块都拥有自己的私有**符号表**（_Symbol Table，一种存储键值对的数据结构_），因为被引入的模块名称会被放置在引入模块的全局**全局符号表**当中，所以模块当中定义的函数能够以**全局符号表**的方式进行使用。因此，模块的作者可以放心的在模块中使用全局变量，而毋须担心与其它用户的变量发生冲突。另一方面，如要需要访问这些模块里定义的全局变量 ，那么可以通过`module_name.variable_name`的方式进行访问。\n\n如果觉得`module_name.variable_name`方式过于繁琐，那么可以通过`from module_name import iitem_name_in_module`语句指定从模块导入的内容，而无须总是在使用的时候添加模块的名称，请见下面的例子：\n\n```py\n# module.py\ndef demo1():\n  print(\"This is demo1!\")\n\ndef demo2():\n  print(\"This is demo2!\")\n```\n\n```py\n# main.py\nfrom module import demo1, demo2\n\ndemo1()\ndemo2()\n\n'''\nThis is demo1!\nThis is demo2!\n'''\n```\n\n当然，如果觉得比较麻烦，还可以使用`from module import *`一次性导入`module`模块当中的内容。但是需要注意的是这样并不能导入模块中以下划线`_`作为前缀的内容，比如下面这样：\n\n```py\n# module.py\ndef _privateDemo():\n  print(\"This is a private demo!\")\n```\n\n```py\nfrom module import *\n\n_privateDemo()\n\n'''\nTraceback (most recent call last):\n  File \"main.py\", line 1, in \u003cmodule\u003e\n    from module import privateDemo\nImportError: cannot import name 'privateDemo'\n'''\n```\n\n\u003e 这种一忺导入全部模块内容的方式在 Python 官方文档中是不被鼓励的，因此在现实开发场景下需要酌情使用。\n\n如果引入模块的名称与当前模块定义的变量或者函数有冲突，那么可以考虑通过`as`关键字使模块中的内容绑定到一个别名上。\n\n```py\n# module.py\ndef demo():\n  print(\"This is another demo!\")\n```\n\n```py\n# main.py\nimport module as m\n\nm.demo()\n\n'''\nThis is another demo!\n'''\n```\n\n当然，也可以将`from...import...as...`结合起来使用，这样做会让代码更加简化。\n\n```py\n# main.py\nfrom module import demo as d\n\nd()\n\n'''\nThis is another demo!\n'''\n```\n\n出于性能方面的考量，一个模块只会在 Python 的每个解释器会话当中被引入一次，所以如果开发人员在解释器运行之后修改了模块的代码，则必须重新启动解释器。当然，如果你只有一个模块需要进行交互式的测试，则可以使用`importlib.reload()`方法暂时解决这个问题。\n\n```py\nimport module\nimport importlib\n\nimportlib.reload(module)\n```\n\n### 以脚本方式执行模块\n\n当在控制台直接执行 Python 脚本文件的时候，模块的`__name__`属性值会被设置为`\"__main__\"`，可以利用这个特性在模块文件在命令行以`python module.py`直接进行执行的时候，进行一些特定的交互和操作。\n\n```py\n# module.py\nif __name__ == \"__main__\":\n    import sys\n    parameter = sys.argv[1]\n    print(parameter)\n```\n\n```bash\n➜  git:(master) ✗ python3 main.py 2018\n2018\n```\n\n### 模块的搜索的路径\n\n当一个模块名字被引入时，Python 解释器会首先搜索内置模块是否存在该名称，如果不存在，则会按照`sys.path`属性的顺序进行搜索。即首先是当前`.py`脚本所在的目录，然后是 Python 环境变量相关的目录，最后进行 Python 安装相关的目录。\n\n```py\nimport sys\nprint(sys.path)\n\n'''\n['/workspace/python-quick-guide/module', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/hank/.local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']\n'''\n```\n\n### 预编译\n\n为了加快模块的加载速度，Pytho 缓存了`__pycache__`目录下每个模块的编译版本至`module.version.pyc`名称下，例如**CPython release 3.6**里的`main.py`模块将会被缓存为`__pycache__/main.cpython-36.pyc`，这样的命名约定可以使不同 Python 版本的编译模块能够同时共存。\n\nPython 根据编译版本检查源代码的修改日期，以确定它是否过期，是否需要重新编译。这是一个完全自动的过程。此外，编译后的模块是独立于平台的，因此相同的库可以在具有不同体系结构的系统之间共享。\n\nPython 在两种情况下不检查缓存。首先，它总是重新编译，不存储直接从命令行加载的模块的结果。其次，如果没有源模块，它不会检查缓存。要支持非源(仅编译)发行版，编译后的模块必须位于源目录中，并且不允许有源模块。\n\nPython 在两种情况下不会检查缓存。首先，从命令行直接加载的模块总是会重新进行编译；其次，如果当前没有源模块时就不会检查缓存。为了支持非源（_仅编译可用_）的发行版，被编译的模块必须位于源目录，并且它们必须不能是一个源模块。\n\n需要提醒一些资深的使用者：\n\n- 你可以使用`-O`或`-OO`控制 Python 命令编译模块的尺寸，参数`-O`会移除 assert 语句，`-OO`会移除 assert 语句和`__doc__`字符串。由于有些程序可能依赖于这些选项，所以只有在知道自己在做什么时才应该使用这此选项。经过优化的模块会拥有一个`opt-`标识并且通常情况下尺寸会更小。但是未来的 Python 版本可能会调整这些优化的效果。\n- 从`.pyc`文件读取的程序并不会比从`.py`文件读取的运行速度更快，`.pyc文件`唯一提高的是加载速度。\n- 模块`compileall`能够为一个目录下的所有模块建立`.pyc`文件。\n\n\u003e Python 内置的标准模块，有些是依赖于操作系统底层实现的，例如`winreg`模块只供在 Windows 系统上使用。但是模块`sys`比较特殊，它可以用于几乎所有平台的 Python 解释器。\n\n### `dir()`方法\n\nPython 内置的`dir()`方法能够以字符串格式输出模块当中所定义的内容。\n\n```py\n# module.py\nvariable = 2018\n\ndef demo():\n    print(\"This is a demo!\")\n```\n\n```py\n# main.py\nimport sys, module\n\nprint(\"main.py里的属性与方法：\", dir()) # 打印当前模块内容\nprint(\"module.py里的属性与方法：\", dir(module)) # 打印指定模块内容\n```\n\n```bash\nmain.py里的属性与方法： ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'module', 'sys']\nmodule.py里的属性与方法： ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'demo', 'variable']\n```\n\n可以通过向`dir()`方法传递内置的标准模块`builtins`来获取 Python 内建的函数和变量。\n\n```py\nimport builtins\n\nprint(dir(builtins))\n```\n\n```bash\n['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']\n```\n\n### 包\n\nPython 将多个模块的集合称为**包**，包通过带点的模块名来构建 Python 的命名空间，例如模块名`A.B`表示在`A`包下建立的`B`子模块。\n\n```py\n# ./directory/module.py\ndef demo():\n    print(\"This is a demo!\")\n```\n\n```py\n# main.py\nimport directory.module\n\ndirectory.module.demo()\n```\n\n```py\n# main.py\nfrom directory.module import demo\n\ndemo()\n```\n\n注意，当使用`from package import item`格式语法的时候，`item`可以是一个子模块、子包、或者是定义在包中的函数、类、变量。这种情况下`import`语句首先会测试`item`是否定义在包中，如果没有则会被认为是一个模块，并且尝试去加载它。如果加载出现问题，则会抛出一个`ImportError`异常。\n\n相反，使用`import item.subitem.subsubitem`格式语句的时候，除最后一个`item`以外每个`item`都必须是包，最后一个项目可以是模块或者包，但不能是前一个`item`中定义的类、函数、变量。\n\n#### `from ... import *`\n\n如果需要引入一个包下的所有子模块，必须显式的提供一个包的索引。如果一个包的`__init__.py`代码里定义了一个名为`__all__`的列表，它将被视为将要被`from package import *`引入的模块名称的列表。例如，对于一个`package`目录内的`__init__.py`文件可能包含如下内容：\n\n```py\n__all__ = [\"echo\", \"surround\", \"reverse\"]\n```\n\n上面意味着`from package import *`将会引入`package`目录下的`echo`、`surround`、`reverse`3 个子模块。如果这里的`__all__`属性没有被定义，则`from package import *`语句就不会将子模块引入当前的命名空间，它只会确保`package`包被引入，并且也会执行`__init__.py`中的其它代码，然后引入包内定义的各种名称（_包括由`__init__.py`以及子模块定义的_）。\n\n#### 通过相对路径引用包\n\nPython 当中，`from...import...`同样可以通过**相对路径**访问包。\n\n```py\nfrom . import package\nfrom .. import package\nfrom ..package import module\n```\n\n\u003e 注意：相对路径的`import`是基于当前模块名称的，由于主模块名称总是`\"__main__\"`，所以用于作为 Python 应用程序的主模块必须始终使用绝对导入。\n\n#### 处理多个目录中的包\n\nPython 中的包支持一个特殊的属性`__path__`，它可以被初始化成一个包含目录名称的列表，这个列表可以在该代码文件执行之前处理包的`__init__.py`。这个变量可以修改的，这样做会影响将来对包中包含的模块和子包的搜索。\n\n\u003e 虽然通常不需要这个特性，但是可以通过它来扩展包中的模块集合。\n\n## 虚拟环境\n\n虚拟环境（_Virtual Environment_）是一个自包含的目录树，用来管理 Python 第 3 方包依赖。不同的 Python 项目可以使用不同的虚拟环境，例如：应用程序`A`可以安装自己的`1.0`版本的虚拟环境，而应用程序`B`具有另一个`2.0`版本的虚拟环境，如果应用程序`B`需要将依赖库升级至`3.0`版本，这并不会影响应用程序`B`的虚拟环境。\n\nPython 官方提供了一个虚拟环境的轻量级实现模块[venv](https://docs.python.org/3.6/library/venv.html#module-venv)，较新版本的 Python 发行包里已经默认内置了其实现，可以直接进行使用。\n\n```\npython3 -m venv my-project\n```\n\n上面的语句执行之后，将会建立一个`my-project`目录，里面包含一个 Python 解释器的拷贝，以及相关的第 3 方依赖库，在 Python3.6.6 下执行得到的目录结构如下：\n\n![venv](python/venv.png)\n\n当建立完成项目的虚拟环境之后，可以通过如下命令进行激活：\n\n```bash\n# On Windows\nmy-project\\Scripts\\activate.bat\n\n# On Unix or MacOS\nsource my-project/bin/activate\n```\n\n激活后将会改变当前 Shell 的显示信息，以提示开发人员当前正在使用的是哪个虚拟环境。\n\n```bash\n➜  /workspace source my-project/bin/activate\n(my-project) ➜  /workspace python\nPython 3.6.6 (default, Sep 12 2018, 18:26:19)\n[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n\u003e\u003e\u003e import sys\n\u003e\u003e\u003e sys.path\n['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/workspace/my-project/lib/python3.6/site-packages']\n```\n\n\u003e [virtualenv](https://virtualenv.pypa.io/en/latest/)是一个第 3 方社区提供的独立 Python 虚拟环境，同时支持 Python2 和 Python3 版本。在 Python3.3 以后，官方提供了上述的`venv`模块原生支持虚拟环境，因此`virtualenv`逐步废弃使用。\n\n## 包管理\n\nPython 可以使用应用程序`pip`安装、升级、移除第三方依赖包，正常情况下`pip`已经伴随 Python 解释器默认安装，如果当前 Python 默认安装的 pip 版本过低，那么可以通过`pip install -U pip`或`python -m pip install --upgrade pip`命令手动进行安装。\n\n```bash\n# 搜索包\n(my-project) ➜  pip search Django\ndjango-bagou (0.1.0)              - Django Websocket for Django\ndjango-maro (0.0.2)               - `django-maro` is utility for django.\ndjango-ide (0.0.5)                - A Django app to develop Django apps\ndjango-hooked (0.1.7)             - WebHooks for Django and Django Rest Framework.\ndjango-six (1.0.4)                - Django-six \u0026#8212;\u0026#8212; Django Compatibility Library\ndjango-umanage (1.1.1)            - Django user management app for django\ndjango-mailwhimp (0.1)            - django-mailwhimp integrates mailchimp into Django\ndjango-jackal (1.6.2)             - Boilerplate for Django and Django REST Framework\ndjango-nadmin (0.1.0)             - django nadmin support django version 1.8 based on django-xadmin\ndjango-listings (0.1)             - django-listings\ndjango-optionsfield (0.2)         - django-optionsfield\ndjango-user (0.2.1)               - Django User\ndjango-uuidfield (0.5.0)          - UUIDField in Django\ndjango-utils (0.0.2)              - Utilities for Django\n... ... ...\n\n# 安装包\n(my-project) ➜  pip install Django\nCollecting Django\n  Using cached https://files.pythonhosted.org/packages/fd/9a/0c028ea0fe4f5803dda1a7afabeed958d0c8b79b0fe762ffbf728db3b90d/Django-2.1.4-py3-none-any.whl\nRequirement already satisfied: pytz in d:\\software\\tech\\python\\lib\\site-packages (from Django) (2018.7)\nInstalling collected packages: Django\nSuccessfully installed Django-2.1.4\n\n# 移除包\n(my-project) ➜  pip uninstall Django\nUninstalling Django-2.1.4:\n  Would remove:\n    d:\\software\\tech\\python\\lib\\site-packages\\django-2.1.4.dist-info\\*\n    d:\\software\\tech\\python\\lib\\site-packages\\django\\*\n    d:\\software\\tech\\python\\scripts\\django-admin.exe\n    d:\\software\\tech\\python\\scripts\\django-admin.py\nProceed (y/n)? y\n  Successfully uninstalled Django-2.1.4\n\n# 安装包的指定版本\n(my-project) ➜  pip install Django==2.1.2\nCollecting Django==2.1.2\n  Downloading https://files.pythonhosted.org/packages/32/ab/22530cc1b2114e6067eece94a333d6c749fa1c56a009f0721e51c181ea53/Django-2.1.2-py3-none-any.whl (7.3MB)\n    100% |████████████████████████████████| 7.3MB 67kB/s\nRequirement already satisfied: pytz in d:\\software\\tech\\python\\lib\\site-packages (from Django==2.1.2) (2018.7)\nInstalling collected packages: Django\nSuccessfully installed Django-2.1.2\n\n# 升级指定包的版本\n(my-project) ➜  pip install --upgrade Django\nCollecting Django\n  Using cached https://files.pythonhosted.org/packages/fd/9a/0c028ea0fe4f5803dda1a7afabeed958d0c8b79b0fe762ffbf728db3b90d/Django-2.1.4-py3-none-any.whl\nRequirement already satisfied, skipping upgrade: pytz in d:\\software\\tech\\python\\lib\\site-packages (from Django) (2018.7)\nInstalling collected packages: Django\n  Found existing installation: Django 2.1.2\n    Uninstalling Django-2.1.2:\n      Successfully uninstalled Django-2.1.2\nSuccessfully installed Django-2.1.4\n\n# 查看包的指定信息\n(my-project) ➜  pip show Django\nName: Django\nVersion: 2.1.4\nSummary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.\nHome-page: https://www.djangoproject.com/\nAuthor: Django Software Foundation\nAuthor-email: foundation@djangoproject.com\nLicense: BSD\nLocation: d:\\software\\tech\\python\\lib\\site-packages\nRequires: pytz\nRequired-by:\n\n# 展示当前虚拟环境下安装的包\n(my-project) ➜  pip list\nPackage    Version\n---------- -------\nDjango     2.1.4\npip        18.1\npytz       2018.7\nsetuptools 39.0.1\nwheel      0.32.3\n```\n\n`pip freeze`将会生成已安装的包列表，但输出格式使用了`pip install`所期望的格式，通常 Python 约定将该列表放置到一个`requirements.txt`文件。\n\n```bash\n(my-project) ➜  pip freeze \u003e requirements.txt\n\n# requirements.txt\ndataclasses==0.6\nDjango==2.1.2\nDjango==1.2.30\npkg-resources==0.0.0\npymongo==3.7.2\npytz==2018.6\nsqlparse==0.2.4\n```\n\n然后可以将`requirements.txt`文件伴随应用程序一起提交至版本管理系统当中，然后其它用户可以在同步代码之后使用`pip install -r requirements.txt`安装所需的包。\n\n```bash\n(my-project) ➜  pip install -r requirements.txt\nRequirement already satisfied: dataclasses==0.6 in ./lib/python3.6/site-packages (from -r requirements.txt (line 1))\nRequirement already satisfied: Django==2.1.2 in ./lib/python3.6/site-packages (from -r requirements.txt (line 2))\nRequirement already satisfied: Django==1.2.30 in ./lib/python3.6/site-packages (from -r requirements.txt (line 3))\nRequirement already satisfied: pkg-resources==0.0.0 in ./lib/python3.6/site-packages (from -r requirements.txt (line 4))\nRequirement already satisfied: pymongo==3.7.2 in ./lib/python3.6/site-packages (from -r requirements.txt (line 5))\nRequirement already satisfied: pytz==2018.6 in ./lib/python3.6/site-packages (from -r requirements.txt (line 6))\nRequirement already satisfied: sqlparse==0.2.4 in ./lib/python3.6/site-packages (from -r requirements.txt (line 7))\n```\n\n## 输入输出\n\nPython 内置了许多方法去完成输入输出操作，这些方法能够将数据以人类可读的形式打印出来，也可以将其写入文件当中供将来使用。\n\n### 输出格式化\n\nPython 提供了两种字符串格式化输出的方法，一种是使用`format()`函数进行格式化输出，另一种是通过`print()`函数的格式化占位符完成。\n\n```py\nprint(\"{}是中国的一个{}\".format(\"成都\", \"省\"))\nprint(\"{0}是中国的一个{1}\".format(\"成都\", \"省\"))\nprint(\"{city}是中国的一个{province}\".format(city=\"成都\", province=\"省\"))\n\n'''\n成都是中国的一个省\n成都是中国的一个省\n成都是中国的一个省\n'''\n```\n\n```py\nprint(\"%s是中国的一个%s\" % (\"成都\",\"省\"))\nprint(\"%(city)s是中国的一个%(province)s\" % {\"city\": \"成都\", \"province\": \"省\"})\n\n'''\n成都是中国的一个省\n成都是中国的一个省\n'''\n```\n\nPython 当中可以使用`str()`和`repr()`方法将任意值转换成为字符串。其中`str()`会返回人类可读的字符串，`repr()`则会生成 Python 解释器能够读取的格式。\n\n```py\nstring = str(\"Hank\\n\");\nrepresent = repr(\"Hank\\n\");\n\nprint(string)\nprint(represent)\n\n'''\nHank\n\n'Hank\\n'\n'''\n```\n\n### 文件读写\n\nPython 当中`open(filename, mode, encoding)`函数会返回一个`file`对象，其中`filename`是需要打开的文件名，`mode`用于标识以何种方式打开文件，`encoding`指定读写操作的编码格式。\n\n| 模式  | 意义                                         |\n| :---- | :------------------------------------------- |\n| `\"r\"` | 以读方式打开（_默认_）。                     |\n| `\"w\"` | 以写方式打开，并清除之前内容。               |\n| `\"x\"` | 创建文件，如果文件已经存在则操作失败。       |\n| `\"a\"` | 以写方式打开，并在之前内容的尾部追加新内容。 |\n| `\"b\"` | 二进制模式。                                 |\n| `\"t\"` | 文本模式（_默认_）。                         |\n| `\"+\"` | 打开一个磁盘文件进行读写操作。               |\n| `\"U\"` | 通用换行模式（_已废弃_）。                   |\n\n使用`file`对象的最佳实践是与`with`关键字结合在一起，从而保证`file`对象总是能在恰当的时间关闭，即使出现异常，使用`with`关键字也比书写等效的`try-finally`简洁，这个在接下来的[对象清理](#对象清理)章节有更详细的讲解。\n\n```py\nwith open(\"demo.txt\", mode = \"r\", encoding=\"utf8\") as file:\n  readData = file.read()\n  print(readData)\n\nfile.close()\n\n'''\n和我在成都的街头走一走 喔哦\n直到所有的灯都熄灭了也不停留\n'''\n```\n\n如果`file`对象已经被`with`关键字或者`close()`方法关闭，后续任何对`file`对象的操作都将会失败，比如下面的例子：\n\n```py\nfile.close()\nfile.read()\n\n'''\nTraceback (most recent call last):\n  File \"demo.py\", line 6, in \u003cmodule\u003e\n    file.read()\nValueError: I/O operation on closed file.\n'''\n```\n\n使用`readline()`方法可以每次只读取一行数据。\n\n```py\nwith open(\"demo.txt\", mode = \"r\", encoding=\"utf8\") as file:\n  readData = file.readline() # 只读取一行数据\n  print(readData)\n\n'''\n和我在成都的街头走一走 喔哦\n'''\n```\n\n当然，也可以通过循环`file`对象来读取目标文件中的每行数据。\n\n```py\nwith open(\"demo.txt\", mode = \"r\", encoding=\"utf8\") as file:\n  for line in file:\n    print(line)\n\n'''\n和我在成都的街头走一走 喔哦\n\n直到所有的灯都熄灭了也不停留\n'''\n```\n\n\u003e 如果需要读取指定文件的全部内容，还可以采用`list(file)`或`file.readlines()`方法。\n\n`write(string)`用于写入字符串内容到文件，并返回写入的字符数量。\n\n```py\nwith open(\"demo.txt\", mode = \"w\", encoding=\"utf8\") as file:\n  print(file.write(\"Hank\"))\n\n'''\n4\n'''\n```\n\n### 对象清理\n\nPython 当中的一些预定义对象会内置清理行为，可以在对象不再需要的时候被自动执行。\n\n```py\nfor line in open(\"myfile.txt\"):\n    print(line, end=\"\")\n```\n\n上面这段代码的问题在于，代码执行完后没有立即关闭打开的文件。这在相对简单的脚本代码中不算问题，但对于更大规模的应用而言就是严重的错误。因此，Python 提供了`with`语句来确保`file`这样的对象在使用后能够被正确的清理和关闭。\n\n```py\nwith open(\"myfile.txt\") as file:\n    for line in file:\n        print(line, end=\"\")\n```\n\n上面语句执行之后，即使读取文件数据时出现问题，`file`对象也能正常关闭，因为`file`对象已经预定义了相关清除行为。\n\n## Python 之禅\n\n可以在 Python 命令行模式输入`import this`得到一份关于 Python 的优秀指导原则**《Python 之禅》**。\n\n- 优美胜于丑陋。\n- 明了胜于晦涩。\n- 简洁胜于复杂。\n- 复杂胜于凌乱。\n- 扁平胜于嵌套。\n- 间隔胜于紧凑。\n- 保持良好可读性。\n- 即便是特例也不可打压破这些规则。\n- 实用性胜过纯粹性。\n- 对错误与异常不能保持沉默，除非你刻意需要这样做。\n- 面对模棱两可拒绝猜测，应该寻找最好的一个解决方案。\n- 虽然动手做好过于什么都不做，但是仔细思考以后再动手胜过于盲目的去做。\n- 如果实现难以解释，这必然是一个坏主意。\n- 如果实现易于解释，这可能是一个好主意。\n- 命名空间是非常好的主意，要善于进行利用。\n\n## 通过 JSON 保存数据\n\nJSON 可以用来保存诸如嵌套的字典或者列表这样的结构化数据，Python 提供了`json`模块来处理 JSON 格式数据，具体使用方法请参见下面的示例代码：\n\n```py\nimport json\n\nstring = json.dumps([28, \"Hank\"])\nprint(string) # [28, \"Hank\"]\n```\n\n也可以在打开文件之后，将文件内容序列化为 JSON 格式。\n\n```py\nimport json\n\nwith open(\"test.json\", mode = \"r\", encoding=\"utf8\") as file:\n  string = json.load(file)\n  print(string) # {'user': 'Hank', 'age': 33}\n```\n\n## 通过 XML 方式合成 SVG\n\nSVG 本质是基于 XML 语言进行描述的矢量图形，由于 Python 内置的`ElementTree`组件类提供了丰富的操作 XML 树形结构的方法；因此在下面这份简单的示例代码当中，将基于`ElementTree`来完成 SVG 图片文件的合并工作。\n\n```py\nimport xml.etree.ElementTree as ET\n\nET.register_namespace('uinika', 'https://uinika.github.io')\n\nempty = ET.parse('./materials/empty.svg')  # 加载ElementTree\n\nroot = empty.getroot()  # 获取ElementTree的根Element\n\npants = ET.parse('./materials/pants.svg').findall('./')\ncoat = ET.parse('./materials/coat.svg').findall('./')\nhair = ET.parse('./materials/hair.svg').findall('./')\nscarf = ET.parse('./materials/scarf.svg').findall('./')\nface = ET.parse('./materials/face.svg').findall('./')\nbang = ET.parse('./materials/bang.svg').findall('./')\nshoes = ET.parse('./materials/shoes.svg').findall('./')\n\ntree = pants + coat + hair + scarf + face + bang + shoes  # 合并图片组件\n\nfor element in tree:\n    root.append(element)  # 向empty的\u003csvg\u003e元素下添加合并后的图片组件\n\nprint(ET.dump(root))  # 打印生成树\n\nempty.write('./svg/merge.svg', 'UTF-8')  # 保存生成树\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuinika%2Fpython-quick-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuinika%2Fpython-quick-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuinika%2Fpython-quick-guide/lists"}