This commit is contained in:
estomm
2020-09-23 13:41:55 +08:00
parent 42a9d72b0a
commit eb8b866c96
18 changed files with 2895 additions and 5 deletions

View File

View File

@@ -0,0 +1,8 @@
> * [pythonguru](https://pythonguru.apachecn.org/#/)
> * [官方教程](https://docs.python.org/zh-cn/3/tutorial/)
> * [标准库API](https://docs.python.org/zh-cn/3/library/index.html)
> python3中所有的数据类型都是对象。包括数值类型int,float,complex)、列表、字典、元组、集合等。包括函数也是对象。
> python3中所有的内建类的对象不具有动态属性。所有的自定义类的对象都有动态属性。

View File

@@ -0,0 +1,216 @@
# Python 数字
> 原文: [https://thepythonguru.com/python-numbers/](https://thepythonguru.com/python-numbers/)
* * *
于 2020 年 5 月 7 日更新
* * *
此数据类型仅支持诸如`1``31.4``-1000``0.000023``88888888`之类的数值。
Python 支持 3 种不同的数字类型。
1. `int`-用于整数值,例如`1``100``2255``-999999``0``12345678`
2. `float`-用于像`2.3``3.14``2.71``-11.0`之类的浮点值。
3. `complex`-适用于`3+2j``-2+2.3j``10j``4.5+3.14j`等复数。
## 整数
* * *
python 中的整数字面值属于`int`类。
```py
>>> i = 100
>>> i
100
```
## 浮点数
* * *
浮点数是带有小数点的值。
```py
>>> f = 12.3
>>> f
12.3
```
需要注意的一点是,当数字运算符的操作数之一是浮点值时,结果将是浮点值。
```py
>>> 3 * 1.5
4.5
```
## 复数
* * *
如您所知,复数由实部和虚部两部分组成,用`j`表示。 您可以这样定义复数:
```py
>>> x = 2 + 3j # where 2 is the real part and 3 is imaginary
```
## 确定类型
* * *
Python 具有`type()`内置函数,可用于确定变量的类型。
```py
>>> x = 12
>>> type(x)
 <class 'int'>
```
## Python 运算符
* * *
Python 具有不同的运算符,可让您在程序中执行所需的计算。
`+``-``*`可以正常工作,其余的运算符需要一些解释。
| 名称 | 含义 | 示例 | 结果 |
| --- | --- | --- | --- |
| `+` | 加法 | `15+20` | `35` |
| `-` | 减法 | `24.5-3.5` | `21.0` |
| `*` | 乘法 | `15*4` | `60` |
| `/` | 浮点除法 | `4/5` | `0.8` |
| `//` | 整数除法 | `4//5` | `0` |
| `**` | 求幂 | `4**2` | `16` |
| `%` | 余数 | `27%4` | `3` |
**浮点除法(`/`**`/`运算符进行除法并以浮点数形式返回结果,这意味着它将始终返回小数部分。 例如
```py
>>> 3/2 
1.5
```
**整数除法(`//`**`//`执行整数除法,即它将截断答案的小数部分并仅返回整数。
```py
>>> 3//2 
1
```
**幂运算符(`**`**:此运算符有助于计算`^b`a 的 b 次幂)。 让我们举个例子:
```py
>>> 2 ** 3 # is same as 2 * 2 * 2
8
```
**余数运算符(`%`**`%`运算符也称为余数或模数运算符。 该运算符除法后返回余数。 例如:
```py
>>> 7 % 2
1
```
## 运算符优先级
* * *
在 python 中,每个表达式都使用运算符优先级进行求值。 让我们以一个例子来阐明它。
```py
>>> 3 * 4 + 1
```
在上面的表达式中,将对哪个运算进行第一个加法或乘法运算? 为了回答这样的问题,我们需要在 python 中引用运算符优先级列表。 下图列出了 python 优先级从高到低的顺序。
![python-operator-precedence1.jpg](img/1bd07b9ee86ea977adf3c113fe0e0939.png)
如您在上表中所见`*`在`+`之上,因此`*`将首先出现,然后加法。 因此,以上表达式的结果将为`13`。
```py
>>> 3 * 4 + 1
>>> 13
```
让我们再举一个例子来说明另一个概念。
```py
>>> 3 + 4 - 2
```
在以上表达式中,将首先进行加法或减法。 从表`+`和`-`的优先级相同,然后将它们从左到右进行求值,即先加法,然后减法。
```py
>>> 3 + 4 - 2
>>> 5
```
该规则的唯一例外是赋值运算符(`=`),它从右到左出现。
```py
a = b = c
```
您可以使用括号`()`更改优先级,例如:
```py
>> 3 * (4 + 1)
>> 15
```
从优先级表中可以看出,`()`具有最高优先级,因此在表达式`3 * (4 + 1)`中,先求值`(4 + 1)`,然后相乘。 因此,您可以使用`()`更改优先级。
## 复合赋值
* * *
这些运算符使您可以编写快捷方式分配语句。 例如:
```py
>>> count = 1
>>> count = count + 1
>>> count
2
```
通过使用增强分配运算符,我们可以将其编写为:
```py
>>> count = 1
>>> count += 1
>>> count
2
```
类似地,您可以将`-``%``//``/``*`和`**`与赋值运算符一起使用以构成扩展赋值运算符。
| 运算符 | 名称 | 示例 | 等价于 |
| --- | --- | --- | --- |
| `+=` | 加法赋值 | `x += 4` | `x = x + 4` |
| `-=` | 减法赋值 | `x -= 2` | `x = x - 2` |
| `*=` | 乘法赋值 | `x *= 5` | `x = x * 5` |
| `/*=` | 除法赋值 | `x /= 5` | `x = x / 5` |
| `//*=` | 整数除法赋值 | `x //= 5` | `x = x // 5` |
| `%*=` | 余数赋值 | `x %= 5` | `x = x % 5` |
| `**=` | 指数赋值 | `x **= 5` | `x = x ** 5` |

View File

@@ -0,0 +1,536 @@
# Python 字符串
> 原文: [https://thepythonguru.com/python-strings/](https://thepythonguru.com/python-strings/)
* * *
于 2020 年 1 月 10 日更新
* * *
python 中的字符串是由单引号或双引号分隔的连续字符系列。 Python 没有任何单独的字符数据类型,因此它们表示为单个字符串。
## 创建字符串
* * *
```py
>>> name = "tom" # a string
>>> mychar = 'a' # a character
```
您还可以使用以下语法创建字符串。
```py
>>> name1 = str() # this will create empty string object
>>> name2 = str("newstring") # string object containing 'newstring'
```
```py
name = "tom" # a string
mychar = 'a' # a character
print(name)
print(mychar)
name1 = str() # this will create empty string object
name2 = str("newstring") # string object containing 'newstring'
print(name1)
print(name2)
```
## Python 中的字符串是不可变的
* * *
这对您而言意味着,一旦创建了字符串,便无法对其进行修改。 让我们以一个例子来说明这一点。
```py
>>> str1 = "welcome"
>>> str2 = "welcome"
```
这里`str1``str2`指的是存储在内存中某个位置的相同字符串对象“`welcome`”。 您可以使用[`id()`](/python-builtin-functions/id/)函数测试`str1`是否与`str2`引用相同的对象。
什么是身份证?
python 中的每个对象都存储在内存中的某个位置。 我们可以使用`id()`获得该内存地址。
```py
>>> id(str1)
78965411
>>> id(str2)
78965411
```
由于`str1``str2`都指向相同的存储位置,因此它们都指向同一对象。
让我们尝试通过向其添加新字符串来修改`str1`对象。
```py
>>> str1 += " mike"
>>> str1
welcome mike
>>> id(str1)
>>> 78965579
```
如您现在所见,`str1`指向完全不同的内存位置,这证明了并置不会修改原始字符串对象而是创建一个新的字符串对象这一点。 同样,数字(即`int`类型)也是不可变的。
试试看:
```py
str1 = "welcome"
str2 = "welcome"
print(id(str1), id(str2))
str1 += " mike"
print(str1)
print(id(str1))
```
## 字符串操作
* * *
字符串索引从`0`开始,因此要访问字符串类型中的第一个字符:
```py
>>> name[0] #
t
```
试一试:
```py
name = "tom"
print(name[0])
print(name[1])
```
`+`运算符用于连接字符串,而`*`运算符是字符串的重复运算符。
```py
>>> s = "tom and " + "jerry"
>>> print(s)
tom and jerry
```
```py
>>> s = "spamming is bad " * 3
>>> print(s)
'spamming is bad spamming is bad spamming is bad '
```
试一试:
```py
s = "tom and " + "jerry"
print(s)
s = "spamming is bad " * 3
print(s)
```
## 字符串切片
* * *
您可以使用`[]`运算符(也称为切片运算符)从原始字符串中提取字符串的子集。
**语法**`s[start:end]`
这将从索引`start`到索引`end - 1`返回字符串的一部分。
让我们举一些例子。
```py
>>> s = "Welcome"
>>> s[1:3]
el
```
一些更多的例子。
```py
>>> s = "Welcome"
>>>
>>> s[:6]
'Welcom'
>>>
>>> s[4:]
'ome'
>>>
>>> s[1:-1]
'elcom'
```
试一试:
```py
s = "Welcome"
print(s[1:3])
print(s[:6])
print(s[4:])
print(s[1:-1])
```
**注意**
`start`索引和`end`索引是可选的。 如果省略,则`start`索引的默认值为`0`,而`end`的默认值为字符串的最后一个索引。
## `ord()`和`chr()`函数
* * *
`ord()`-函数返回字符的 ASCII 码。
`chr()`-函数返回由 ASCII 数字表示的字符。
```py
>>> ch = 'b'
>>> ord(ch)
98
>>> chr(97)
'a'
>>> ord('A')
65
```
试一试:
```py
ch = 'b'
print(ord(ch))
print(chr(97))
print(ord('A'))
```
## Python 中的字符串函数
* * *
| 函数名称 | 函数说明 |
| --- | --- |
| `len ()` | 返回字符串的长度 |
| `max()` | 返回具有最高 ASCII 值的字符 |
| `min()` | 返回具有最低 ASCII 值的字符 |
```py
>>> len("hello")
5
>>> max("abc")
'c'
>>> min("abc")
'a'
```
试一试:
```py
print(len("hello"))
print(max("abc"))
print(min("abc"))
```
## `in`和`not in`运算符
* * *
您可以使用`in``not in`运算符检查另一个字符串中是否存在一个字符串。 他们也被称为会员运营商。
```py
>>> s1 = "Welcome"
>>> "come" in s1
True
>>> "come" not in s1
False
>>>
```
试一试:
```py
s1 = "Welcome"
print("come" in s1)
print("come" not in s1)
```
## 字符串比较
* * *
您可以使用[`>``<``<=``<=``==``!=`)比较两个字符串。 Python 按字典顺序比较字符串,即使用字符的 ASCII 值。
假设您将`str1`设置为`"Mary"`并将`str2`设置为`"Mac"`。 比较`str1`和`str2`的前两个字符(`M`和`M`)。 由于它们相等,因此比较后两个字符。 因为它们也相等,所以比较了前两个字符(`r`和`c`)。 并且因为`r`具有比`c`更大的 ASCII 值,所以`str1`大于`str2`。
这里还有更多示例:
```py
>>> "tim" == "tie"
False
>>> "free" != "freedom"
True
>>> "arrow" > "aron"
True
>>> "right" >= "left"
True
>>> "teeth" < "tee"
False
>>> "yellow" <= "fellow"
False
>>> "abc" > ""
True
>>>
```
试一试:
```py
print("tim" == "tie")
print("free" != "freedom")
print("arrow" > "aron")
print("right" >= "left")
print("teeth" < "tee")
print("yellow" <= "fellow")
print("abc" > "")
```
## 使用`for`循环迭代字符串
* * *
字符串是一种序列类型,也可以使用`for`循环进行迭代(要了解有关`for`循环的更多信息,[请单击此处](/python-loops/))。
```py
>>> s = "hello"
>>> for i in s:
... print(i, end="")
hello
```
**注意**
默认情况下,`print()`函数用换行符打印字符串,我们通过传递名为`end`的命名关键字参数来更改此行为,如下所示。
```py
print("my string", end="\n") # this is default behavior
print("my string", end="") # print string without a newline
print("my string", end="foo") # now print() will print foo after every string
```
试一试:
```py
s = "hello"
for i in s:
print(i, end="")
```
## 测试字符串
* * *
python 中的字符串类具有各种内置方法,可用于检查不同类型的字符串。
| 方法名称 | 方法说明 |
| --- | --- |
| `isalnum()` | 如果字符串是字母数字,则返回`True` |
| `isalpha()` | 如果字符串仅包含字母,则返回`True` |
| `isdigit()` | 如果字符串仅包含数字,则返回`True` |
| `isidentifier()` | 返回`True`是字符串是有效的标识符 |
| `islower()` | 如果字符串为小写,则返回`True` |
| `isupper()` | 如果字符串为大写则返回`True` |
| `isspace()` | 如果字符串仅包含空格,则返回`True` |
```py
>>> s = "welcome to python"
>>> s.isalnum()
False
>>> "Welcome".isalpha()
True
>>> "2012".isdigit()
True
>>> "first Number".isidentifier()
False
>>> s.islower()
True
>>> "WELCOME".isupper()
True
>>> " \t".isspace()
True
```
试一试:
```py
s = "welcome to python"
print(s.isalnum())
print("Welcome".isalpha())
print("2012".isdigit())
print("first Number".isidentifier())
print(s.islower())
print("WELCOME".isupper())
print(" \t".isspace())
```
## 搜索子串
* * *
| 方法名称 | 方法说明 |
| --- | --- |
| `endwith(s1: str): bool` | 如果字符串以子字符串`s1`结尾,则返回`True` |
| `startswith(s1: str): bool` | 如果字符串以子字符串`s1`开头,则返回`True` |
| `count(s: str): int` | 返回字符串中子字符串出现的次数 |
| `find(s1): int` | 返回字符串中`s1`起始处的最低索引,如果找不到字符串则返回`-1` |
| `rfind(s1): int` | 从字符串中`s1`的起始位置返回最高索引,如果找不到字符串则返回`-1` |
```py
>>> s = "welcome to python"
>>> s.endswith("thon")
True
>>> s.startswith("good")
False
>>> s.find("come")
3
>>> s.find("become")
-1
>>> s.rfind("o")
15
>>> s.count("o")
3
>>>
```
试一试:
```py
s = "welcome to python"
print(s.endswith("thon"))
print(s.startswith("good"))
print(s.find("come"))
print(s.find("become"))
print(s.rfind("o"))
print(s.count("o"))
```
## 转换字符串
* * *
| 方法名称 | 方法说明 |
| --- | --- |
| `capitalize(): str` | 返回此字符串的副本,仅第一个字符大写。 |
| `lower(): str` | 通过将每个字符转换为小写来返回字符串 |
| `upper(): str` | 通过将每个字符转换为大写来返回字符串 |
| `title(): str` | 此函数通过大写字符串中每个单词的首字母来返回字符串 |
| `swapcase(): str` | 返回一个字符串,其中小写字母转换为大写,大写字母转换为小写 |
| `replace(old, new): str` | 此函数通过用新字符串替换旧字符串的出现来返回新字符串 |
```py
s = "string in python"
>>>
>>> s1 = s.capitalize()
>>> s1
'String in python'
>>>
>>> s2 = s.title()
>>> s2
'String In Python'
>>>
>>> s = "This Is Test"
>>> s3 = s.lower()
>>> s3
'this is test'
>>>
>>> s4 = s.upper()
>>> s4
'THIS IS TEST'
>>>
>>> s5 = s.swapcase()
>>> s5
'tHIS iS tEST'
>>>
>>> s6 = s.replace("Is", "Was")
>>> s6
'This Was Test'
>>>
>>> s
'This Is Test'
>>>
```
试一试:
```py
s = "string in python"
s1 = s.capitalize()
print(s1)
s2 = s.title()
print(s2)
s = "This Is Test"
s3 = s.lower()
print(s3)
s4 = s.upper()
print(s4)
s5 = s.swapcase()
print(s5)
s6 = s.replace("Is", "Was")
print(s6)
print(s)
```

316
Python/python3/2.3列表.md Normal file
View File

@@ -0,0 +1,316 @@
# Python 列表
> 原文: [https://thepythonguru.com/python-lists/](https://thepythonguru.com/python-lists/)
* * *
于 2020 年 1 月 7 日更新
* * *
列表类型是 python 的列表类定义的另一种序列类型。 列表允许您以非常简单的方式添加,删除或处理元素。 列表与数组非常相似。
## 在 python 中创建列表
* * *
您可以使用以下语法创建列表。
```py
>>> l = [1, 2, 3, 4]
```
在此,列表中的每个元素都用逗号分隔,并用一对方括号(`[]`)包围。 列表中的元素可以是相同类型或不同类型。 例如:
```py
l2 = ["this is a string", 12]
```
创建列表的其他方式。
```py
list1 = list() # Create an empty list
list2 = list([22, 31, 61]) # Create a list with elements 22, 31, 61
list3 = list(["tom", "jerry", "spyke"]) # Create a list with strings
list5 = list("python") # Create a list with characters p, y, t, h, o, n
```
**注意**
列表是可变的。
## 访问列表中的元素
* * *
您可以使用索引运算符(`[]`)访问列表中的各个元素。 列表索引从`0`开始。
```py
>>> l = [1,2,3,4,5]
>>> l[1] # access second element in the list
2
>>> l[0] # access first element in the list
1
```
## 常用列表操作
* * *
| 方法名称 | 描述 |
| --- | --- |
| `x in s` | 如果元素`x`在序列`s`中,则为`True`,否则为`False` |
| `x not in s` | 如果元素`x`不在序列`s`中,则为`True`,否则为`False` |
| `s1 + s2` | 连接两个序列`s1``s2` |
| `s * n``n * s` | 连接序列`s``n`个副本 |
| `s[i]` | 序列`s`的第`i`个元素。 |
| `len(s)` | 序列`s`的长度,也就是元素数量。 |
| `min(s)` | 序列`s`中最小的元素。 |
| `max(s)` | 序列`s`中最大的元素。 |
| `sum(s)` | 序列`s`中所有数字的总和。 |
| `for`循环 | 在`for`循环中从左到右遍历元素。 |
## 列表函数示例
* * *
```py
>>> list1 = [2, 3, 4, 1, 32]
>>> 2 in list1
True
>>> 33 not in list1
True
>>> len(list1) # find the number of elements in the list
5
>>> max(list1) # find the largest element in the list
32
>>> min(list1) # find the smallest element in the list
1
>>> sum(list1) # sum of elements in the list
42
```
## 列表切片
* * *
切片运算符(`[start:end]`)允许从列表中获取子列表。 它的工作原理类似于字符串。
```py
>>> list = [11,33,44,66,788,1]
>>> list[0:5] # this will return list starting from index 0 to index 4
[11,33,44,66,788]
```
```py
>>> list[:3]
[11,33,44]
```
类似于字符串`start`的索引是可选的,如果省略,它将为`0`
```py
>>> list[2:]
[44,66,788,1]
```
`end`索引也是可选的,如果省略,它将被设置为列表的最后一个索引。
**注意**
如果为`start >= end`,则`list[start : end]`将返回一个空列表。 如果`end`指定的位置超出列表的`end`,则 Python 将使用`end`的列表长度。
## 列表中的`+`和`*`运算符
* * *
`+`运算符加入两个列表。
```py
>>> list1 = [11, 33]
>>> list2 = [1, 9]
>>> list3 = list1 + list2
>>> list3
[11, 33, 1, 9]
```
`*`操作符复制列表中的元素。
```py
>>> list4 = [1, 2, 3, 4]
>>> list5 = list4 * 3
>>> list5
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
```
## `in`或`not in`运算符
* * *
`in`运算符用于确定列表中是否存在元素。 成功则返回`True`;失败则返回`False`
```py
>>> list1 = [11, 22, 44, 16, 77, 98]
>>> 22 in list1
True
```
同样,`not in``in`运算符相反。
```py
>>> 22 not in list1
False
```
## 使用`for`循环遍历列表
* * *
如前所述,列表是一个序列并且也是可迭代的。 意味着您可以使用`for`循环遍历列表的所有元素。
```py
>>> list = [1,2,3,4,5]
>>> for i in list:
... print(i, end=" ")
1 2 3 4 5
```
## 常用列表方法和返回类型
* * *
| 方法 | 描述 |
| --- | --- |
| `append(x: object): None` | 在列表的末尾添加元素`x`并返回`None`。 |
| `count(x: object): int` | 返回元素`x`在列表中出现的次数。 |
| `append(l: list): None` | 将`l`中的所有元素附加到列表中并返回`None`。 |
| `index(x: object): int` | 返回列表中第一次出现的元素`x`的索引 |
| `insert(index: int, x: object): None` | 在给定索引处插入元素`x`。 请注意,列表中的第一个元素具有索引`0`并返回`None`。 |
| `remove(x: object): None` | 从列表中删除第一次出现的元素`x`并返回`None` |
| `reverse(): None` | 反转列表并返回`None` |
| `sort(): None` | 按升序对列表中的元素进行排序并返回`None`。 |
| `pop(i): object` | 删除给定位置的元素并返回它。 参数`i`是可选的。 如果未指定,则`pop()`删除并返回列表中的最后一个元素。 |
|`copy():object`|返回一个复制|
|`clear()`|移除所有元素`del a[:]`|
|`list.extend(iterable)`|使用可迭代对象中的所有元素来扩展列表。|
```py
>>> list1 = [2, 3, 4, 1, 32, 4]
>>> list1.append(19)
>>> list1
[2, 3, 4, 1, 32, 4, 19]
>>> list1.count(4) # Return the count for number 4
2
>>> list2 = [99, 54]
>>> list1.extend(list2)
>>> list1
[2, 3, 4, 1, 32, 4, 19, 99, 54]
>>> list1.index(4) # Return the index of number 4
2
>>> list1.insert(1, 25) # Insert 25 at position index 1
>>> list1
[2, 25, 3, 4, 1, 32, 4, 19, 99, 54]
>>>
>>> list1 = [2, 25, 3, 4, 1, 32, 4, 19, 99, 54]
>>> list1.pop(2)
3
>>> list1
[2, 25, 4, 1, 32, 4, 19, 99, 54]
>>> list1.pop()
54
>>> list1
[2, 25, 4, 1, 32, 4, 19, 99]
>>> list1.remove(32) # Remove number 32
>>> list1
[2, 25, 4, 1, 4, 19, 99]
>>> list1.reverse() # Reverse the list
>>> list1
[99, 19, 4, 1, 4, 25, 2]
>>> list1.sort() # Sort the list
>>> list1
[1, 2, 4, 4, 19, 25, 99]
>>>
```
## 列表推导式
* * *
**注意**
本主题需要具有 [Python 循环](/loops/)的使用知识。
列表理解为创建列表提供了一种简洁的方法。 它由包含表达式的方括号组成,后跟`for`子句,然后是零个或多个`for``if`子句。
这里有些例子:
```py
>>> list1 = [ x for x in range(10) ]
>>> list1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
>>>
>>> list2 = [ x + 1 for x in range(10) ]
>>> list2
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>>
>>>
>>> list3 = [ x for x in range(10) if x % 2 == 0 ]
>>> list3
[0, 2, 4, 6, 8]
>>>
>>>
>>> list4 = [ x *2 for x in range(10) if x % 2 == 0 ]
[0, 4, 8, 12, 16]
```
## 列表作为栈使用
列表方法使得列表作为堆栈非常容易,最后一个插入,最先取出(“后进先出”)。要添加一个元素到堆栈的顶端,使用 append() 。要从堆栈顶部取出一个元素,使用 pop() ,不用指定索引。例如
```
>>>
>>> stack = [3, 4, 5]
>>> stack.append(6)
>>> stack.append(7)
>>> stack
[3, 4, 5, 6, 7]
>>> stack.pop()
7
>>> stack
[3, 4, 5, 6]
>>> stack.pop()
6
>>> stack.pop()
5
>>> stack
[3, 4]
```
## 列表作为队列使用
列表也可以用作队列,其中先添加的元素被最先取出 (“先进先出”);然而列表用作这个目的相当低效。因为在列表的末尾添加和弹出元素非常快,但是在列表的开头插入或弹出元素却很慢 (因为所有的其他元素都必须移动一位)。
若要实现一个队列,可使用 collections.deque它被设计成可以快速地从两端添加或弹出元素。例如
```
>>> from collections import deque
>>> queue = deque(["Eric", "John", "Michael"])
>>> queue.append("Terry") # Terry arrives
>>> queue.append("Graham") # Graham arrives
>>> queue.popleft() # The first to arrive now leaves
'Eric'
>>> queue.popleft() # The second to arrive now leaves
'John'
>>> queue # Remaining queue in order of arrival
deque(['Michael', 'Terry', 'Graham'])
```

220
Python/python3/2.4字典.md Normal file
View File

@@ -0,0 +1,220 @@
# Python 字典
> 原文: [https://thepythonguru.com/python-dictionaries/](https://thepythonguru.com/python-dictionaries/)
* * *
于 2020 年 1 月 7 日更新
* * *
字典是一种 python 数据类型,用于存储键值对。 它使您可以使用键快速检索,添加,删除,修改值。 字典与我们在其他语言上称为关联数组或哈希的非常相似。
**注意**
字典是可变的。
## 创建字典
* * *
可以使用一对大括号(`{}`)创建字典。 字典中的每个项目都由一个键,一个冒号,一个值组成。 每个项目都用逗号(`,`)分隔。 让我们举个例子。
```py
friends = {
'tom' : '111-222-333',
'jerry' : '666-33-111'
}
```
这里`friends`是有两个项目的字典。 需要注意的一点是,键必须是可哈希的类型,但是值可以是任何类型。 字典中的每个键都必须是唯一的。
```py
>>> dict_emp = {} # this will create an empty dictionary
```
* dict() 构造函数可以直接从键值对序列里创建字典。
```py
>>>
>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'guido': 4127, 'jack': 4098}
```
* 此外,字典推导式可以从任意的键值表达式中创建字典
```py
>>>
>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}
```
* 当关键字是简单字符串时,有时直接通过关键字参数来指定键值对更方便
```py
>>>
>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'guido': 4127, 'jack': 4098}
```
## 检索,修改和向字典中添加元素
* * *
要从字典中获取项目,请使用以下语法:
```py
>>> dictionary_name['key']
```
```py
>>> friends['tom']
'111-222-333'
```
如果字典中存在键,则将返回值,否则将引发`KeyError`异常。 要添加或修改项目,请使用以下语法:
```py
>>> dictionary_name['newkey'] = 'newvalue'
```
```py
>>> friends['bob'] = '888-999-666'
>>> friends
 {'tom': '111-222-333', 'bob': '888-999-666', 'jerry': '666-33-111'}
```
## 从字典中删除项目
* * *
```py
>>> del dictionary_name['key']
```
```py
>>>  del friends['bob']
>>>  friends
{'tom': '111-222-333', 'jerry': '666-33-111'}
```
如果找到键,则该项目将被删除,否则将抛出`KeyError`异常。
## 遍历字典中的项目
* * *
您可以使用`for`循环遍历字典中的元素。
```py
>>> friends = {
... 'tom' : '111-222-333',
... 'jerry' : '666-33-111'
...}
>>>
>>> for key in friends:
... print(key, ":", friends[key])
...
tom : 111-222-333
jerry : 666-33-111
>>>
>>>
```
## 查找字典的长度
* * *
您可以使用`len()`函数查找字典的长度。
```py
>>> len(friends)
2
```
## `in`和`not in`运算符
* * *
`in``not in`运算符检查字典中是否存在键。
```py
>>> 'tom' in friends
True
>>> 'tom' not in friends
False
```
## 字典中的相等测试
* * *
`==``!=`运算符告诉字典是否包含相同的项目。
```py
>>> d1 = {"mike":41, "bob":3}
>>> d2 = {"bob":3, "mike":41}
>>> d1 == d2
True
>>> d1 != d2
False
>>>
```
**注意**
您不能使用`<``>``>=``<=`等其他关系运算符来比较字典。
## 字典方法
* * *
Python 提供了几种内置的方法来处理字典。
| 方法 | 描述 |
| --- | --- |
| `popitem()` | 返回字典中随机选择的项目,并删除所选项目。 |
| `clear()` | 删除字典中的所有内容 |
| `keys()` | 以元组形式返回字典中的键 |
| `values()` | 以元组形式返回字典中的值 |
| `get(key)` | 键的返回值,如果找不到键,则返回`None`,而不是引发`KeyError`异常 |
| `pop(key)` | 从字典中删除该项目,如果找不到该键,则会抛出`KeyError` |
```py
>>> friends = {'tom': '111-222-333', 'bob': '888-999-666', 'jerry': '666-33-111'}
>>>
>>> friends.popitem()
('tom', '111-222-333')
>>>
>>> friends.clear()
>>>
>>> friends
{}
>>>
>>> friends = {'tom': '111-222-333', 'bob': '888-999-666', 'jerry': '666-33-111'}
>>>
>>> friends.keys()
dict_keys(['tom', 'bob', 'jerry'])
>>>
>>> friends.values()
dict_values(['111-222-333', '888-999-666', '666-33-111'])
>>>
>>> friends.get('tom')
'111-222-333'
>>>
>>> friends.get('mike', 'Not Exists')
'Not Exists'
>>>
>>> friends.pop('bob')
'888-999-666'
>>>
>>> friends
{'tom': '111-222-333', 'jerry': '666-33-111'}
```

View File

@@ -0,0 +1,97 @@
# Python 元组
> 原文: [https://thepythonguru.com/python-tuples/](https://thepythonguru.com/python-tuples/)
* * *
于 2020 年 1 月 7 日更新
* * *
在 Python 中,元组与列表非常相似,但是一旦创建了元组,就无法添加,删除,替换和重新排序元素。
**注意**
元组是不可变的。
## 创建一个元组
* * *
```py
>>> t1 = () # creates an empty tuple with no data
>>>
>>> t2 = (11,22,33)
>>>
>>> t3 = tuple([1,2,3,4,4]) # tuple from array
>>>
>>> t4 = tuple("abc") # tuple from string
```
## 元组函数
* * *
元组也可以使用`max()``min()``len()``sum()`之类的函数。
```py
>>> t1 = (1, 12, 55, 12, 81)
>>> min(t1)
1
>>> max(t1)
81
>>> sum(t1)
161
>>> len(t1)
5
```
## 元组迭代
* * *
元组可使用`for`循环进行迭代,[在此处了解有关 for 循环的更多信息](/python-loops/)。
```py
>>> t = (11,22,33,44,55)
>>> for i in t:
... print(i, end=" ")
>>> 11 22 33 44 55
```
## 元组切片
* * *
切片运算符在元组中的作用与在列表和字符串中的作用相同。
```py
>>> t = (11,22,33,44,55)
>>> t[0:2]
(11,22)
```
## `in`和`not in`运算符
* * *
您可以使用`in``not in`运算符检查元组中项的存在,如下所示。
```py
>>> t = (11,22,33,44,55)
>>> 22 in t
True
>>> 22 not in t
False
```
在下一章中,我们将学习 [python 数据类型转换](/datatype-conversion/)。
* * *
* * *

View File

@@ -0,0 +1,91 @@
# 数据类型转换
> 原文: [https://thepythonguru.com/datatype-conversion/](https://thepythonguru.com/datatype-conversion/)
* * *
于 2020 年 1 月 7 日更新
* * *
偶尔,您会希望将一种类型的数据类型转换为另一种类型。 数据类型转换也称为类型转换。
## 将`int`转换为`float`
* * *
要将`int`转换为`float`,可以使用`float()`函数。
```py
>>> i = 10
>>> float(i)
10.0
```
## 将`float`转换为`int`
* * *
要将`float`转换为`int`,您需要使用`int()`函数。
```py
>>> f = 14.66
>>> int(f)
14
```
## 将字符串转换为`int`
* * *
要将`string`转换为`int`,请使用`int()`函数。
```py
>>> s = "123"
>>> int(s)
123
```
**提示**
如果字符串包含非数字字符,则`int()`将引发`ValueError`异常。
## 将数字转换为字符串
* * *
要将数字转换为字符串,请使用`str()`函数。
```py
>>> i = 100
>>> str(i)
"100"
>>> f = 1.3
str(f)
'1.3'
```
## 舍入数字
* * *
四舍五入数字是通过`round()`函数完成的。
**语法**`round(number[, ndigits])`
```py
>>> i = 23.97312
>>> round(i, 2)
23.97
```
接下来,我们将介绍[控制语句](/python-control-statements/)。
* * *
* * *

View File

@@ -0,0 +1,40 @@
## 集合定义
Python也包含有 集合 类型。集合是由不重复元素组成的无序的集。它的基本用法包括成员检测和消除重复元素。集合对象也支持像 联合,交集,差集,对称差分等数学运算。
花括号或 set() 函数可以用来创建集合。注意:要创建一个空集合你只能用 set() 而不能用 {},因为后者是创建一个空字典,这种数据结构我们会在下一节进行讨论。
以下是一些简单的示例
```py
>>>
>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket) # show that duplicates have been removed
{'orange', 'banana', 'pear', 'apple'}
>>> 'orange' in basket # fast membership testing
True
>>> 'crabgrass' in basket
False
>>> # Demonstrate set operations on unique letters from two words
...
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a # unique letters in a
{'a', 'r', 'b', 'c', 'd'}
>>> a - b # letters in a but not in b
{'r', 'd', 'b'}
>>> a | b # letters in a or b or both
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b # letters in both a and b
{'a', 'c'}
>>> a ^ b # letters in a or b but not both
{'r', 'd', 'b', 'm', 'z', 'l'}
```
类似于 列表推导式,集合也支持推导式形式
```py
>>>
>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}
```

View File

@@ -0,0 +1,294 @@
# 数据类型和变量
> 原文: [https://thepythonguru.com/datatype-varibles/](https://thepythonguru.com/datatype-varibles/)
* * *
于 2020 年 1 月 7 日更新
* * *
## 变量名和关键字
变量是命名位置,用于存储对内存中存储的对象的引用。 我们为变量和函数选择的名称通常称为标识符。 在 Python 中,标识符必须遵守以下规则。
1. 所有标识符都必须以字母或下划线(`_`)开头,您不能使用数字。 例如:`my_var`是有效的标识符,但`1digit`不是。
2. 标识符可以包含字母,数字和下划线(`_`)。 例如:`error_404``_save`是有效的标识符,但`$name$`(不允许`$`)和`#age`(不允许`#`)是无效的标识符。
3. 它们可以是任何长度。
4. 标识符不能是关键字。 关键字是 Python 用于特殊目的的保留字)。 以下是 Python 3 中的关键字。
```python
False class finally is return
None continue for lambda try
True def from nonlocal while
and del global not with
as elif if or yield
pass else import assert
break except in raise
```
## 变量赋值
> * 变量和值是一对关系。变量赋值,是把数据的引用或者说地址,传递给某个变量,进行标记。所有的变量都是引用。指向具体的地址。
> * 引用和指针不同。引用是同一个数据的别名。指针是一个数据类型,存储的是指向数据的地址。引用不是一个数据类型。是一种变量形式。
> * 数值类型与字符串类型的值是不可变的。一旦定义就不能更改,内存中会分配固定大小的位置。更改会创建一个新的值。
> * 列表、元组、字典等复合类型的值是可变的。可以通过下表索引来操作内部元素的值。其地址不会变化,更改不会创建新的复合类型。
> * 自定义类型class的值也是可变的。在同一个地址的一个对象可以更改对象内部的数据。
* * *
值是程序可以使用的基本东西。 例如:`1``11``3.14``"hello"`均为值。 在编程术语中,它们通常也称为字面值。 字面值可以是不同的类型,例如`1``11``int`类型,`3.14``float``"hello"``string`。 记住,在 Python 中,所有东西都是对象,甚至是基本数据类型,例如 intfloatstring我们将在后面的章节中对此进行详细说明。
在 Python 中,您不需要提前声明变量类型。 解释器通过包含的数据自动检测变量的类型。 要将值赋给变量等号(`=`)。 `=`符号也称为赋值运算符。
以下是变量声明的一些示例:
```py
x = 100 # x is integer
pi = 3.14 # pi is float
empname = "python is great" # empname is string
a = b = c = 100 # this statement assign 100 to c, b and a.
```
试试看:
```py
x = 100 # x is integer
pi = 3.14 # pi is float
empname = "python is great" # empname is string
a = b = c = 100 # this statement assign 100 to c, b and a.
print(x) # print the value of variable x
print(pi) # print the value of variable pi
print(empname) # print the value of variable empname
print(a, b, c) # print the value of variable a, b, and c, simultaneously
```
**提示**
将值分配给变量后,该变量本身不存储值。 而是,变量仅将对象的引用(地址)存储在内存中。 因此,在上面的清单中,变量`x`存储对`100``int`对象)的引用(或地址)。 变量`x`本身不存储对象`100`
## 注释
* * *
注释是说明程序目的或程序工作方式的注释。 注释不是 Python 解释器在运行程序时执行的编程语句。 注释也用于编写程序文档。 在 Python 中,任何以井号(`#`)开头的行均被视为注释。 例如:
```py
# This program prints "hello world"
print("hello world")
```
试一试:
```py
# This program prints "hello world"
print("hello world")
```
在此清单中,第 1 行是注释。 因此在运行程序时Python 解释器将忽略它。
我们还可以在语句末尾写注释。 例如:
```py
# This program prints "hello world"
print("hello world") # display "hello world"
```
当注释以这种形式出现时,它们称为最终注释。
试一试:
```py
# This program prints "hello world"
print("hello world") # display hello world
```
## 多重赋值
* * *
同时赋值或多重赋值允许我们一次将值赋给多个变量。 同时分配的语法如下:
```py
var1, var2, ..., varn = exp1, exp2, ..., expn
```
该语句告诉 Python 求值右边的所有表达式,并将它们分配给左边的相应变量。 例如:
```py
a, b = 10, 20
print(a)
print(b)
```
试一试:
```py
a, b = 10, 20
print(a)
print(b)
```
当您想交换两个变量的值时,同时分配非常有帮助。 例如:
```py
>>> x = 1 # initial value of x is 1
>>> y = 2 # initial value of y is 2
>>> y, x = x, y # assign y value to x and x value to y
```
**预期输出**
```py
>>> print(x) # final value of x is 2
2
>>> print(y) # final value of y is 1
1
```
试一试:
```py
x = 1 # initial value of x is 1
y = 2 # initial value of y is 2
y, x = x, y # assign y value to x and x value to y
print(x) # final value of x is 2
print(y) # final value of y is 1
```
## Python 数据类型
* * *
Python 即有 5 种标准数据类型。
1. 数值
2. 字符串
3. 列表
4. 元组
5. 字典
6. 布尔值 - 在 Python 中,`True``False`是布尔字面值。 但是以下值也被认为是`False`
* `0` - `0``0.0`
* `[]` - 空列表,`()`-空元组,`{}`-空字典,`''`
* `None`
## 从控制台接收输入
* * *
`input()`函数用于从控制台接收输入。
**语法** `input([prompt]) -> string`
`input()`函数接受一个名为`prompt`的可选字符串参数,并返回一个字符串。
```py
>>> name = input("Enter your name: ")
>>> Enter your name: tim
>>> name
'tim'
```
试一试:
```py
name = input("Enter your name: ")
print(name)
```
请注意,即使输入了数字,`input()`函数也始终返回字符串。 要将其转换为整数,可以使用`int()`或 [`eval()`](/python-builtin-functions/eval/)函数。
```py
>>> age = int(input("Enter your age: "))
Enter your age: 22
>>> age
22
>>> type(age)
<class 'int'>
```
试一试:
```py
age = int(input("Enter your age: "))
print(age)
print(type(age))
```
## 导入模块
* * *
Python 使用模块组织代码。 Python 随附了许多内置模块,可用于例如数学相关函数的`math`模块,正则表达式的`re`模块,与操作系统相关的函数的`os`模块等。
要使用模块,我们首先使用`import`语句将其导入。 其语法如下:
```py
import module_name
```
我们还可以使用以下语法导入多个模块:
```py
import module_name_1, module_name_2
```
这是一个例子
```py
>>> import math, os
>>>
>>> math.pi
3.141592653589793
>>>
>>> math.e
2.718281828459045
>>>
>>>
>>> os.getcwd() # print current working directory
>>> '/home/user'
>>>
```
试一试:
```py
import math, os
print(math.pi)
print(math.e)
print(os.getcwd())
```
在此清单中,第一行导入了`math``os`模块中定义的所有函数,类,变量和常量。 要访问模块中定义的对象,我们首先编写模块名称,后跟点(`.`),然后编写对象本身的名称。 (即类或函数或常量或变量)。 在上面的示例中,我们从`math`数学访问两个常见的数学常数`pi``e`。 在下一行中,我们将调用`os`模块的`getcwd()`函数,该函数将打印当前工作目录。
在下一章中,我们将介绍 Python 中的[数字](/python-numbers/)。
* * *
* * *

View File

@@ -0,0 +1,100 @@
## if语句
```
>>> x = int(input("Please enter an integer: "))
Please enter an integer: 42
>>> if x < 0:
... x = 0
... print('Negative changed to zero')
... elif x == 0:
... print('Zero')
... elif x == 1:
... print('Single')
... else:
... print('More')
...
More
```
## for语句
对任意序列进行迭代(例如列表或字符串),条目的迭代顺序与它们在序列中出现的顺序一致。
```py
>>> # Measure some strings:
... words = ['cat', 'window', 'defenestrate']
>>> for w in words:
... print(w, len(w))
...
cat 3
window 6
defenestrate 12
```
在遍历同一个集合时修改该集合的代码可能很难获得正确的结果。通常,更直接的做法是循环遍历该集合的副本或创建新集合:
```py
# Strategy: Iterate over a copy
for user, status in users.copy().items():
if status == 'inactive':
del users[user]
# Strategy: Create a new collection
active_users = {}
for user, status in users.items():
if status == 'active':
active_users[user] = status
```
## else循环语句
try 语句中的 else 子句会在未发生异常时执行,而循环中的 else 子句则会在未发生 break 时执行。
循环语句可能带有 else 子句;它会在循环耗尽了可迭代对象 (使用 for) 或循环条件变为假值 (使用 while) 时被执行,但不会在循环被 break 语句终止时被执行。
```py
>>> for n in range(2, 10):
... for x in range(2, n):
... if n % x == 0:
... print(n, 'equals', x, '*', n//x)
... break
... else:
... # loop fell through without finding a factor
... print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
```
## break语句
break 语句,和 C 中的类似,用于跳出最近的 for 或 while 循环.
## continue语句
continue 语句也是借鉴自 C 语言,表示继续循环中的下一次迭代:
```
>>> for num in range(2, 10):
... if num % 2 == 0:
... print("Found an even number", num)
... continue
... print("Found an odd number", num)
Found an even number 2
Found an odd number 3
Found an even number 4
Found an odd number 5
Found an even number 6
Found an odd number 7
Found an even number 8
Found an odd number 9
```
## pass语句
pass 语句什么也不做。当语法上需要一个语句,但程序需要什么动作也不做时,可以使用它。例如:
```py
>>>
>>> while True:
... pass # Busy-wait for keyboard interrupt (Ctrl+C)
...
```

283
Python/python3/4函数.md Normal file
View File

@@ -0,0 +1,283 @@
## 定义函数
```py
>>> def fib(n): # write Fibonacci series up to n
... """Print a Fibonacci series up to n."""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')
... a, b = b, a+b
... print()
...
>>> # Now call the function we just defined:
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
```
> 参数都是引用传递。
* 关键字 def 引入一个函数 定义。它必须后跟函数名称和带括号的形式参数列表。构成函数体的语句从下一行开始,并且必须缩进。
* 函数体的第一个语句可以(可选的)是字符串文字。用来生成文档
* 函数的 执行 会引入一个用于函数局部变量的新符号表。 更确切地说,函数中所有的变量赋值都将存储在局部符号表中;而变量引用会首先在局部符号表中查找,然后是外层函数的局部符号表,再然后是全局符号表,最后是内置名称的符号表。
* 在函数被调用时,实际参数(实参)会被引入被调用函数的本地符号表中;因此,实参是通过 按值调用 传递的(其中 值 始终是对象 引用 而不是对象的值。1 当一个函数调用另外一个函数时,将会为该调用创建一个新的本地符号表。
## 默认参数(可选参数)(函数定义)
```py
def ask_ok(prompt, retries=4, reminder='Please try again!'):
while True:
ok = input(prompt)
if ok in ('y', 'ye', 'yes'):
return True
if ok in ('n', 'no', 'nop', 'nope'):
return False
retries = retries - 1
if retries < 0:
raise ValueError('invalid user response')
print(reminder)
```
这个函数可以通过几种方式调用:
* 只给出必需的参数ask_ok('Do you really want to quit?')
* 给出一个可选的参数ask_ok('OK to overwrite the file?', 2)
* 或者给出所有的参数ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
> 多次调用默认参数会共享
```
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
```
## 位置参数和关键字参数(函数调用)
也可以使用形如 kwarg=value 的 关键字参数 来调用函数。例如下面的函数:
```py
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.")
print("-- Lovely plumage, the", type)
print("-- It's", state, "!")
```
接受一个必需的参数voltage和三个可选的参数state, action和 type。这个函数可以通过下面的任何一种方式调用:
```py
parrot(1000) # 1 positional argument
parrot(voltage=1000) # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump') # 3 positional arguments
parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
```
但下面的函数调用都是无效的:
```py
parrot() # required argument missing
parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument
parrot(110, voltage=220) # duplicate value for the same argument
parrot(actor='John Cleese') # unknown keyword argument
```
* 在函数调用中,关键字参数必须跟随在位置参数的后面。
* 传递的所有关键字参数必须与函数接受的其中一个参数匹配(比如 actor 不是函数 parrot 的有效参数),它们的顺序并不重要。
* 不能对同一个参数多次赋值。
## 复合参数(函数定义)
当存在一个形式为 `**name` 的最后一个形参时,它会接收一个字典 ,其中包含除了与已有形参相对应的关键字参数以外的所有关键字参数。
这可以与一个形式为 `*name`,接收一个包含除了已有形参列表以外的位置参数的 元组 的形参组合使用 (*name 必须出现在 **name 之前。)
例如,如果我们这样定义一个函数:
```py
def cheeseshop(kind, *arguments, **keywords):
print("-- Do you have any", kind, "?")
print("-- I'm sorry, we're all out of", kind)
for arg in arguments:
print(arg)
print("-" * 40)
for kw in keywords:
print(kw, ":", keywords[kw])
```
它可以像这样调用:
```py
cheeseshop("Limburger", "It's very runny, sir.",
"It's really very, VERY runny, sir.",
shopkeeper="Michael Palin",
client="John Cleese",
sketch="Cheese Shop Sketch")
```
当然它会打印:
```
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch
```
注意打印时关键字参数的顺序保证与调用函数时提供它们的顺序是相匹配的。
## 特殊参数(函数定义)
默认情况下,函数的参数传递形式可以是位置参数或是显式的关键字参数。 为了确保可读性和运行效率,限制允许的参数传递形式是有意义的,这样开发者只需查看函数定义即可确定参数项是仅按位置、按位置也按关键字,还是仅按关键字传递。
函数的定义看起来可以像是这样:
```py
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
```
* / 和 * 是可选的。 如果使用这些符号则表明可以通过何种形参将参数值传递给函数:仅限位置、位置或关键字,以及仅限关键字。 关键字形参也被称为命名形参。
* 如果函数定义中未使用 / 和 *,则参数可以按位置或按关键字传递给函数。
### 函数实例
* 请考虑以下示例函数定义并特别注意 / 和 * 标记:
```py
>>>
>>> def standard_arg(arg):
... print(arg)
...
>>> def pos_only_arg(arg, /):
... print(arg)
...
>>> def kwd_only_arg(*, arg):
... print(arg)
...
>>> def combined_example(pos_only, /, standard, *, kwd_only):
... print(pos_only, standard, kwd_only)
```
* 第一个函数定义 standard_arg 是最常见的形式,对调用方式没有任何限制,参数可以按位置也可以按关键字传入:
```py
>>>
>>> standard_arg(2)
2
>>> standard_arg(arg=2)
2
```
* 第二个函数 pos_only_arg 在函数定义中带有 /,限制仅使用位置形参。:
```py
>>>
>>> pos_only_arg(1)
1
>>> pos_only_arg(arg=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: pos_only_arg() got an unexpected keyword argument 'arg'
```
* 第三个函数 kwd_only_args 在函数定义中通过 * 指明仅允许关键字参数:
```
>>>
>>> kwd_only_arg(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given
>>> kwd_only_arg(arg=3)
3
```
* 而最后一个则在同一函数定义中使用了全部三种调用方式:
```
>>>
>>> combined_example(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() takes 2 positional arguments but 3 were given
>>> combined_example(1, 2, kwd_only=3)
1 2 3
>>> combined_example(1, standard=2, kwd_only=3)
1 2 3
>>> combined_example(pos_only=1, standard=2, kwd_only=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() got an unexpected keyword argument 'pos_only'
```
* 最后,请考虑这个函数定义,它的位置参数 name 和 **kwds 之间由于存在关键字名称 name 而可能产生潜在冲突:
```
def foo(name, **kwds):
return 'name' in kwds
```
任何调用都不可能让它返回 True因为关键字 'name' 将总是绑定到第一个形参。 例如:
```
>>>
>>> foo(1, **{'name': 2})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() got multiple values for argument 'name'
>>>
```
* 但使用 / (仅限位置参数) 就可能做到,因为它允许 name 作为位置参数,也允许 'name' 作为关键字参数的关键字名称:
```
def foo(name, /, **kwds):
return 'name' in kwds
>>> foo(1, **{'name': 2})
True
```
* 换句话说,仅限位置形参的名称可以在 **kwds 中使用而不产生歧义。
### 使用指导
* 如果你希望形参名称对用户来说不可用,则使用仅限位置形参。 这适用于形参名称没有实际意义,以及当你希望强制规定调用时的参数顺序,或是需要同时收受一些位置形参和任意关键字形参等情况。
* 当形参名称有实际意义,以及显式指定形参名称可使函数定义更易理解,或者当你想要防止用户过于依赖传入参数的位置时,则使用仅限关键字形参。
* 对于 API 来说,使用仅限位置形参可以防止形参名称在未来被修改时造成破坏性的 API 变动。
## 解包参数列表(函数调用)
当参数已经在列表或元组中但要为需要单独位置参数的函数调用解包时,会发生相反的情况。例如,内置的 range() 函数需要单独的 start 和 stop 参数。如果它们不能单独使用,可以使用 * 操作符 来编写函数调用以便从列表或元组中解包参数:
```py
>>>
>>> list(range(3, 6)) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # call with arguments unpacked from a list
[3, 4, 5]
```
同样的方式,字典可使用 ** 操作符 来提供关键字参数:
```py
>>>
>>> def parrot(voltage, state='a stiff', action='voom'):
... print("-- This parrot wouldn't", action, end=' ')
... print("if you put", voltage, "volts through it.", end=' ')
... print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
```
> 使用*和**来对元组参数和字典参数进行解包,与定义复合参数的函数相对应。
## Lambda表达式函数定义
可以用 lambda 关键字来创建一个小的匿名函数。这个函数返回两个参数的和: lambda a, b: a+b 。Lambda函数可以在需要函数对象的任何地方使用。它们在语法上限于单个表达式。从语义上来说它们只是正常函数定义的语法糖。与嵌套函数定义一样lambda函数可以引用所包含域的变量:
```py
>>>
>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43
```

View File

@@ -0,0 +1,90 @@
## 序列类型
* 列表
* 字典
* 元组
* 集合
## 5.6. 循环的技巧¶
* 当在字典中循环时,用 items() 方法可将关键字和对应的值同时取出
```py
>>>
>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
... print(k, v)
...
gallahad the pure
robin the brave
```
* 当在序列中循环时,用 enumerate() 函数可以将索引位置和其对应的值同时取出
```py
>>>
>>> for i, v in enumerate(['tic', 'tac', 'toe']):
... print(i, v)
...
0 tic
1 tac
2 toe
```
* 当同时在两个或更多序列中循环时,可以用 zip() 函数将其内元素一一匹配。
```py
>>>
>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
... print('What is your {0}? It is {1}.'.format(q, a))
...
What is your name? It is lancelot.
What is your quest? It is the holy grail.
What is your favorite color? It is blue.
```
* 如果要逆向循环一个序列,可以先正向定位序列,然后调用 reversed() 函数
```py
>>>
>>> for i in reversed(range(1, 10, 2)):
... print(i)
...
9
7
5
3
1
```
如果要按某个指定顺序循环一个序列,可以用 sorted() 函数,它可以在不改动原序列的基础上返回一个新的排好序的序列
```py
>>>
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
... print(f)
...
apple
banana
orange
pear
```
有时可能会想在循环时修改列表内容,一般来说改为创建一个新列表是比较简单且安全的
```py
>>>
>>> import math
>>> raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
>>> filtered_data = []
>>> for value in raw_data:
... if not math.isnan(value):
... filtered_data.append(value)
...
>>> filtered_data
[56.2, 51.7, 55.3, 52.5, 47.8]
```
## 比较序列和其他类型
序列对象通常可以与相同序列类型的其他对象比较。 这种比较使用 字典式 顺序:首先比较开头的两个对应元素,如果两者不相等则比较结果就由此确定;如果两者相等则比较之后的两个元素,以此类推,直到有一个序列被耗尽。 如果要比较的两个元素本身又是相同类型的序列,则会递归地执行字典式顺序比较。 如果两个序列中所有的对应元素都相等,则两个序列也将被视为相等。 如果一个序列是另一个的初始子序列,则较短的序列就被视为较小(较少)。 对于字符串来说,字典式顺序是使用 Unicode 码位序号对单个字符排序。 下面是一些相同类型序列之间比较的例子:
```py
(1, 2, 3) < (1, 2, 4)
[1, 2, 3] < [1, 2, 4]
'ABC' < 'C' < 'Pascal' < 'Python'
(1, 2, 3, 4) < (1, 2, 4)
(1, 2) < (1, 2, -1)
(1, 2, 3) == (1.0, 2.0, 3.0)
(1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4)
```

118
Python/python3/6模块.md Normal file
View File

@@ -0,0 +1,118 @@
## 模块的定义
Python有一种方法可以把定义放在一个文件里并在脚本或解释器的交互式实例中使用它们。这样的文件被称作 模块 ;模块中的定义可以 导入 到其它模块或者 主 模块(你在顶级和计算器模式下执行的脚本中可以访问的变量集合)。
```py
# Fibonacci numbers module
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
```
现在进入Python解释器并用以下命令导入该模块:
```py
>>>
>>> import fibo
```
在当前的符号表中,这并不会直接进入到定义在 fibo 函数内的名称;它只是进入到模块名 fibo 中。你可以用模块名访问这些函数:
```py
>>>
>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'
```
如果你想经常使用某个函数,你可以把它赋值给一个局部变量:
```
>>>
>>> fib = fibo.fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
```
import 语句有一个变体,它可以把名字从一个被调模块内直接导入到现模块的符号表里。例如:
```py
>>>
>>> from fibo import fib, fib2
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
```
## 以脚本的方式执行模块
当你用下面方式运行一个Python模块:
```
python fibo.py <arguments>
```
模块里的代码会被执行,就好像你导入了模块一样,但是 `__name__ `被赋值为` "__main__"`。 这意味着通过在你的模块末尾添加这些代码:
```py
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
```
## 模块搜索路径
当一个名为 spam 的模块被导入的时候,解释器首先寻找具有该名称的内置模块。如果没有找到,然后解释器从 sys.path 变量给出的目录列表里寻找名为 spam.py 的文件。sys.path 初始有这些目录地址:
* 包含输入脚本的目录(或者未指定文件时的当前目录)。
* PYTHONPATH 一个包含目录名称的列表它和shell变量 PATH 有一样的语法)。
* 取决于安装的默认设置
## 编译过的Python文件
为了加速模块载入Python在 __pycache__ 目录里缓存了每个模块的编译后版本,名称为 module.version.pyc ,其中名称中的版本字段对编译文件的格式进行编码; 它一般使用Python版本号。
## 标准模块
Python附带了一个标准模块库在单独的文档Python库参考以下称为“库参考”中进行了描述。一些模块内置于解释器中它们提供对不属于语言核心但仍然内置的操作的访问以提高效率或提供对系统调用等操作系统原语的访问。这些模块的集合是一个配置选项它也取决于底层平台。
## dir() 函数
内置函数 dir() 用于查找模块定义的名称。 它返回一个排序过的字符串列表:
```py
>>>
>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
```
## 包
包是一种通过用“带点号的模块名”来构造 Python 模块命名空间的方法。 例如,模块名 A.B 表示 A 包中名为 B 的子模块。正如模块的使用使得不同模块的作者不必担心彼此的全局变量名称一样,使用加点的模块名可以使得 NumPy 或 Pillow 等多模块软件包的作者不必担心彼此的模块名称一样。
```
sound/ Top-level package
__init__.py Initialize the sound package
formats/ Subpackage for file format conversions
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/ Subpackage for sound effects
__init__.py
echo.py
surround.py
reverse.py
...
filters/ Subpackage for filters
__init__.py
equalizer.py
vocoder.py
karaoke.py
...
```

View File

@@ -0,0 +1,83 @@
## 格式化字符串
### 入侵式格式化
* 要使用 格式化字符串字面值 ,请在字符串的开始引号或三引号之前加上一个 f 或 F 。在此字符串中,你可以在 { 和 } 字符之间写可以引用的变量或字面值的 Python 表达式。
```py
>>>
>>> year = 2016
>>> event = 'Referendum'
>>> f'Results of the {year} {event}'
'Results of the 2016 Referendum'
>>> import math
>>> print(f'The value of pi is approximately {math.pi:.3f}.')
The value of pi is approximately 3.142.
```
### 函数式格式化
* 字符串的 str.format() 方法需要更多的手动操作。你仍将使用 { 和 } 来标记变量将被替换的位置,并且可以提供详细的格式化指令,但你还需要提供要格式化的信息。
```py
>>>
>>> yes_votes = 42_572_654
>>> no_votes = 43_132_495
>>> percentage = yes_votes / (yes_votes + no_votes)
>>> '{:-9} YES votes {:2.2%}'.format(yes_votes, percentage)
' 42572654 YES votes 49.67%'
```
### 字符串拼接
* 最后,你可以使用字符串切片和连接操作自己完成所有的字符串处理,以创建你可以想象的任何布局。字符串类型有一些方法可以执行将字符串填充到给定列宽的有用操作。
## 调试字符串
当你不需要花哨的输出而只是想快速显示某些变量以进行调试时,可以使用 repr() or str() 函数将任何值转化为字符串。
```py
>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'
>>> repr(s)
"'Hello, world.'"
>>> str(1/7)
'0.14285714285714285'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
>>> print(s)
The value of x is 32.5, and y is 40000...
>>> # The repr() of a string adds string quotes and backslashes:
... hello = 'hello, world\n'
>>> hellos = repr(hello)
>>> print(hellos)
'hello, world\n'
>>> # The argument to repr() may be any Python object:
... repr((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"
```
## format
str.format() 方法的基本用法如下所示:
```py
>>>
>>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
We are the knights who say "Ni!"
```
花括号和其中的字符(称为格式字段)将替换为传递给 str.format() 方法的对象。花括号中的数字可用来表示传递给 str.format() 方法的对象的位置。
```py
>>>
>>> print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
>>> print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam
```
如果在 str.format() 方法中使用关键字参数,则使用参数的名称引用它们的值。:
```py
>>>
>>> print('This {food} is {adjective}.'.format(
... food='spam', adjective='absolutely horrible'))
This spam is absolutely horrible.
```
位置和关键字参数可以任意组合:
```py
>>>
>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
other='Georg'))
The story of Bill, Manfred, and Georg.
```

View File

@@ -0,0 +1,164 @@
## 错误
* 语法错误又称解析错误可能是你在学习Python 时最容易遇到的错误:
```py
>>>
>>> while True print('Hello world')
File "<stdin>", line 1
while True print('Hello world')
^
SyntaxError: invalid syntax
```
* 解析器会输出出现语法错误的那一行,并显示一个“箭头”,指向这行里面检测到第一个错误。
## 异常
即使语句或表达式在语法上是正确的,但在尝试执行时,它仍可能会引发错误。 在执行时检测到的错误被称为 异常。
```py
>>> 10 * (1/0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 4 + spam*3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly
```
## 异常处理
可以编写处理所选异常的程序。请看下面的例子,它会要求用户一直输入,直到输入的是一个有效的整数,但允许用户中断程序(使用 Control-C 或操作系统支持的其他操作);请注意用户引起的中断可以通过引发 KeyboardInterrupt 异常来指示。:
```py
>>>
>>> while True:
... try:
... x = int(input("Please enter a number: "))
... break
... except ValueError:
... print("Oops! That was no valid number. Try again...")
...
```
try 语句的工作原理如下。
* 首先,执行 try 子句 try 和 except 关键字之间的(多行)语句)。
* 如果没有异常发生,则跳过 except 子句 并完成 try 语句的执行。
* 如果在执行try 子句时发生了异常,则跳过该子句中剩下的部分。然后,如果异常的类型和 except 关键字后面的异常匹配,则执行 except 子句 ,然后继续执行 try 语句之后的代码。
* 如果发生的异常和 except 子句中指定的异常不匹配,则将其传递到外部的 try 语句中;如果没有找到处理程序,则它是一个 未处理异常,执行将停止并显示如上所示的消息。
最后的 except 子句可以省略异常名,以用作通配符。但请谨慎使用,因为以这种方式很容易掩盖真正的编程错误!它还可用于打印错误消息,然后重新引发异常(同样允许调用者处理异常):
```py
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise
```
try ... except 语句有一个可选的 else 子句,在使用时必须放在所有的 except 子句后面。对于在try 子句不引发异常时必须执行的代码来说很有用。例如:
```py
for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except OSError:
print('cannot open', arg)
else:
print(arg, 'has', len(f.readlines()), 'lines')
f.close()
```
使用 else 子句比向 try 子句添加额外的代码要好,因为它避免了意外捕获由 try ... except 语句保护的代码未引发的异常。
## 定义异常
## 抛出异常
raise 语句允许程序员强制发生指定的异常。例如:
```py
>>>
>>> raise NameError('HiThere')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: HiThere
```
## 清理操作
定义清理操作
try 语句有另一个可选子句,用于定义必须在所有情况下执行的清理操作。例如:
```py
>>>
>>> try:
... raise KeyboardInterrupt
... finally:
... print('Goodbye, world!')
...
Goodbye, world!
KeyboardInterrupt
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
```
* 如果存在 finally 子句,则 finally 子句将作为 try 语句结束前的最后一项任务被执行。 finally 子句不论 try 语句是否产生了异常都会被执行。 以下几点讨论了当异常发生时一些更复杂的情况:
* 如果在执行 try 子句期间发生了异常,该异常可由一个 except 子句进行处理。 如果异常没有被某个 except 子句所处理,则该异常会在 finally 子句执行之后被重新引发。
* 异常也可能在 except 或 else 子句执行期间发生。 同样地,该异常会在 finally 子句执行之后被重新引发。
* 如果在执行 try 语句时遇到一个 break, continue 或 return 语句,则 finally 子句将在执行 break, continue 或 return 语句之前被执行。
* 如果 finally 子句中包含一个 return 语句,则返回值将来自 finally 子句的某个 return 语句的返回值,而非来自 try 子句的 return 语句的返回值。
```py
>>> def divide(x, y):
... try:
... result = x / y
... except ZeroDivisionError:
... print("division by zero!")
... else:
... print("result is", result)
... finally:
... print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'
```
正如你所看到的finally 子句在任何情况下都会被执行。 两个字符串相除所引发的 TypeError 不会由 except 子句处理,因此会在 finally 子句执行后被重新引发。
在实际应用程序中finally 子句对于释放外部资源(例如文件或者网络连接)非常有用,无论是否成功使用资源。
## 预定义的清理操作
某些对象定义了在不再需要该对象时要执行的标准清理操作,无论使用该对象的操作是成功还是失败。请查看下面的示例,它尝试打开一个文件并把其内容打印到屏幕上。:
```py
for line in open("myfile.txt"):
print(line, end="")
```
这个代码的问题在于,它在这部分代码执行完后,会使文件在一段不确定的时间内处于打开状态。这在简单脚本中不是问题,但对于较大的应用程序来说可能是个问题。 with 语句允许像文件这样的对象能够以一种确保它们得到及时和正确的清理的方式使用。:
```py
with open("myfile.txt") as f:
for line in f:
print(line, end="")
```
执行完语句后,即使在处理行时遇到问题,文件 f 也始终会被关闭。和文件一样,提供预定义清理操作的对象将在其文档中指出这一点。

225
Python/python3/9类.md Normal file
View File

@@ -0,0 +1,225 @@
## 类
特点:
* 类提供了一种组合数据和功能的方法。 创建一个新类意味着创建一个新的对象 类型,从而允许创建一个该类型的新 实例 。 每个类的实例可以拥有保存自己状态的属性。 一个类的实例也可以有改变自己状态的(定义在类中的)方法。
* 类继承机制允许多个基类,派生类可以覆盖它基类的任何方法,一个方法可以调用基类中相同名称的的方法。对象可以包含任意数量和类型的数据。和模块一样,类也拥有 Python 天然的动态特性:它们在运行时创建,可以在创建后修改。
> 只有自定义的类的对象才会有同态属性,系统内建的对象,不允许有动态属性。
## 名称和对象
对象具有个性,多个名称(在多个作用域内)可以绑定到同一个对象。这在其他语言中称为别名。
> 变量存储对象的引用。对象变量作为参数传递时,传递的是对象的引用。
## 类定义语法
最简单的类定义看起来像这样:
```py
class ClassName:
<statement-1>
.
.
.
<statement-N>
```
## 类的对象
类对象支持两种操作:属性引用和实例化。
### 属性引用
属性引用 使用 Python 中所有属性引用所使用的标准语法: obj.name。 有效的属性名称是类对象被创建时存在于类命名空间中的所有名称。 因此,如果类定义是这样的:
```py
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
```
那么 MyClass.i 和 MyClass.f 就是有效的属性引用,将分别返回一个整数和一个函数对象。 类属性也可以被赋值,因此可以通过赋值来更改 MyClass.i 的值。
### 实例化
类的 实例化 使用函数表示法。 可以把类对象视为是返回该类的一个新实例的不带参数的函数。 举例来说(假设使用上述的类):
x = MyClass()
创建类的新 实例 并将此对象分配给局部变量 x。
实例化操作(“调用”类对象)会创建一个空对象。 许多类喜欢创建带有特定初始状态的自定义实例。 为此类定义可能包含一个名为 __init__() 的特殊方法,就像这样:
```py
def __init__(self):
self.data = []
```
当一个类定义了 __init__() 方法时,类的实例化操作会自动为新创建的类实例发起调用 __init__()。 因此在这个示例中,可以通过以下语句获得一个经初始化的新实例:
```py
x = MyClass()
```
当然__init__() 方法还可以有额外参数以实现更高灵活性。 在这种情况下,提供给类实例化运算符的参数将被传递给 __init__()。 例如,:
```py
>>>
>>> class Complex:
... def __init__(self, realpart, imagpart):
... self.r = realpart
... self.i = imagpart
...
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)
```
## 继承
当然,如果不支持继承,语言特性就不值得称为“类”。派生类定义的语法如下所示:
```py
class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>
```
名称 BaseClassName 必须定义于包含派生类定义的作用域中。 也允许用其他任意表达式代替基类名称所在的位置。 这有时也可能会用得上,例如,当基类定义在另一个模块中的时候:
```py
class DerivedClassName(modname.BaseClassName):
```
## 多重继承
Python也支持一种多重继承。 带有多个基类的类定义语句如下所示:
```py
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
.
.
<statement-N>
```
## 私有变量
那种仅限从一个对象内部访问的“私有”实例变量在 Python 中并不存在。 但是,大多数 Python 代码都遵循这样一个约定:带有一个下划线的名称 (例如 _spam) 应该被当作是 API 的非公有部分 (无论它是函数、方法或是数据成员)。 这应当被视为一个实现细节,可能不经通知即加以改变。
由于存在对于类私有成员的有效使用场景(例如避免名称与子类所定义的名称相冲突),因此存在对此种机制的有限支持,称为 名称改写。 任何形式为 __spam 的标识符(至少带有两个前缀下划线,至多一个后缀下划线)的文本将被替换为 _classname__spam其中 classname 为去除了前缀下划线的当前类名称。 这种改写不考虑标识符的句法位置,只要它出现在类定义内部就会进行。
名称改写有助于让子类重载方法而不破坏类内方法调用。例如:
```py
class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable)
def update(self, iterable):
for item in iterable:
self.items_list.append(item)
__update = update # private copy of original update() method
class MappingSubclass(Mapping):
def update(self, keys, values):
# provides new signature for update()
# but does not break __init__()
for item in zip(keys, values):
self.items_list.append(item)
```
## 迭代器
到目前为止,您可能已经注意到大多数容器对象都可以使用 for 语句:
```py
for element in [1, 2, 3]:
print(element)
for element in (1, 2, 3):
print(element)
for key in {'one':1, 'two':2}:
print(key)
for char in "123":
print(char)
for line in open("myfile.txt"):
print(line, end='')
```
这种访问风格清晰、简洁又方便。 迭代器的使用非常普遍并使得 Python 成为一个统一的整体。 在幕后for 语句会在容器对象上调用 iter()。 该函数返回一个定义了 __next__() 方法的迭代器对象,此方法将逐一访问容器中的元素。 当元素用尽时__next__() 将引发 StopIteration 异常来通知终止 for 循环。 你可以使用 next() 内置函数来调用 __next__() 方法;这个例子显示了它的运作方式:
```py
>>>
>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
next(it)
StopIteration
```
看过迭代器协议的幕后机制,给你的类添加迭代器行为就很容易了。 定义一个 __iter__() 方法来返回一个带有 __next__() 方法的对象。 如果类已定义了 __next__(),则 __iter__() 可以简单地返回 self:
```py
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
>>>
>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
... print(char)
...
m
a
p
s
```
## 生成器
生成器 是一个用于创建迭代器的简单而强大的工具。 它们的写法类似于标准的函数,但当它们要返回数据时会使用 yield 语句。 每次在生成器上调用 next() 时,它会从上次离开的位置恢复执行(它会记住上次执行语句时的所有数据值)。 一个显示如何非常容易地创建生成器的示例如下:
```py
def reverse(data):
for index in range(len(data)-1, -1, -1):
yield data[index]
>>>
>>> for char in reverse('golf'):
... print(char)
...
f
l
o
g
```
可以用生成器来完成的操作同样可以用前一节所描述的基于类的迭代器来完成。 但生成器的写法更为紧凑,因为它会自动创建 __iter__() 和 __next__() 方法。
## 生成器表达式
某些简单的生成器可以写成简洁的表达式代码,所用语法类似列表推导式,将外层为圆括号而非方括号。 这种表达式被设计用于生成器将立即被外层函数所使用的情况。 生成器表达式相比完整的生成器更紧凑但较不灵活,相比等效的列表推导式则更为节省内存。
示例:
```py
>>>
>>> sum(i*i for i in range(10)) # sum of squares
285
>>> xvec = [10, 20, 30]
>>> yvec = [7, 5, 3]
>>> sum(x*y for x,y in zip(xvec, yvec)) # dot product
260
>>> unique_words = set(word for line in page for word in line.split())
>>> valedictorian = max((student.gpa, student.name) for student in graduates)
>>> data = 'golf'
>>> list(data[i] for i in range(len(data)-1, -1, -1))
['f', 'l', 'o', 'g']
```