# 一页纸 Python 手册

基于 Learn X in Y minutes (opens new window) 进行修改

# 注释

# 单行注释: 用井字符开头

# 多行注释: 需要用 3 个双引号或者单引号包裹
"""
多行字符串用三个引号包裹
也常被用来做多行注释
可以是单引号, 也可以是双引号
注意, 必须是英文符号
"""

# 在调试代码时, 经常把某一部分代码注释掉, 来临时跳过某些代码, 进行对比测试
1
2
3
4
5
6
7
8
9
10
11

# 数据类型

# Python的数据类型:
#     整数 int
#     浮点数 float
#     字符串 str
#     布尔值 bool
#     数组 array
#     元组 turple
#     字典 dict
#     集合 set
#     空对象 None

# 用来获取数据类型的函数
type()

# 整数 integer
3  # → 3
type(3) # → <class 'int'>
a = int(input('请输入数字')) # 想要获取输入的数字, 记得要转化一下

# 浮点数 float
1.0  # → 1.0
type(1.0)  # → <class 'float'>

# 布尔值 boolean
True  # 注意, True 和 False 都必须是首字母大写
False
type(True)  # → <class 'bool'>

# 整数也可以当作布尔值
0 and 2 # → 0
-5 or 0 # → -5
0 == False # → True
2 == True # → False
1 == True # → True

# 这些值都算是 False: None、0、空字符串、空列表、空字典
# 而其他的所有的值都是 True
# 注意, 没有所谓空集合, 因为空集合就是空字典 {}
bool(0)  # → False
bool("")  # → False
bool([]) # → False
bool({}) # → False

# 字符串 string
type("Hello World") # → <class 'str'>

# 字符串用单引号或者双引号都可以
"这是个字符串"
'这也是个字符串'

# 字符串可以被当作列表
"This is a string"[0]  # → 'T'

# 列表 list
li = []
type(li)  # → <class 'list'>

# 元组 tuple
# 元组是不可改变的序列
tup = (1, 2, 3)
type(tup)  # → <class 'tuple'>
tup[0]   # → 1
tup[0] = 3  # 抛出TypeError, 因为元组不能被修改


# 字典 dictionary
empty_dict = {}
type(empty_dict)  # → <class 'dict'>
# 字典的初始化
filled_dict = {"one": 1, "two": 2, "three": 3}

# 集合 set
empty_set = set()
type(empty_set)  # → <class 'set'>
# 初始化一个集合, 和字典的初始化相似
some_set = {1, 1, 2, 2, 3, 4}   # some_set现在是{1, 2, 3, 4}

# None是一个对象
None  # → None

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

# 变量

# 在变量赋值前, 不用提前声明变量
# 变量名用数字、字母、下划线组成, 但是数字不能放在变量名的第1位
# 变量名对大小写敏感, 也就是说 thisName 不等于 thisname

# 建议变量命名使用小写字母, 然后用下划线来分隔
some_var = 5
some_var  # → 5

# 变量命名也可以包含数字, 但是数字不能放在命名的第 1 位
4some_var # 报错, SyntaxError: invalid syntax

# 访问未赋值的变量会抛出异常
# 参考教程后面“流程控制:异常”的部分, 来学习异常处理
some_unknown_var  # 抛出NameError

# 全局变量
global some_var
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 操作符

# 操作符: 算术操作符

“操作符”的英文名是 Operator, 也称为“运算符”, 包括算术运算、比较运算、逻辑运算... 但是, 我建议用“操作符”来指称, 而不要用“运算符”来指称.

这是因为“运算”这个词给我们的心理暗示是数学上的加减乘除运算, 我们直观上不会认为比较操作、逻辑操作是一种运算 ( 尽管对于计算机来说, 的确是运算 ), 因此大脑面对“比较运算”和“逻辑运算”这些词的时候会产生不协调感. 而“操作符”是一种中性的表述, "操作"可以包括算术运算、比较、逻辑判断...

# Python 中的算术和我们在学校学的算数没有太大区别
1 + 1  # → 2
8 - 1  # → 7
10 * 2  # → 20

# “除法”例外, 除法的结果会自动转换成浮点数
35 / 5  # → 7.0
5 / 3  # → 1.6666666666666667
-5 / 3  # → -1.6666666666666667

# 两个斜杠//的叫“整数除法”, 需要向下取整
# 本质是 floor 操作, floor = 地板, 也就是说取接近计算结果最近的那个整数
5 // 3     # → 1
5.0 // 3.0 # → 1.0 # 浮点数也可以进行整数除法
-5 // 3  # → -2 # 注意这里! 记住, 整数除法的结果都是向下取整, 也就是往小的取整
-5.0 // 3.0 # → -2.0

# 如果想要截取除法结果的整数部分, 需要使用 math 模块的 trunc 函数
import math
math.trunc(1 / 2)  # → 0
math.trunc(-5 / 3)  # → -1

# 浮点数的运算结果也是浮点数
3 * 2.0 # → 6.0

# 取余数, 也叫“取模”、“模除”
7 % 3 # → 1

# x 的 y 次方
2**4 # → 16
3**2 # → 9

# 平方
5**2 # → 25
9**2 # → 81
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 操作符: 逻辑操作符

# 布尔值
True
False

# 逻辑操作符, 注意 and 和 or 都是小写
True and False # → False
False or True # → True

# 逻辑操作符, 用 not 取非
not True  # → False
not False  # → True

# 整数也可以当作布尔值
0 and 2 # → 0
-5 or 0 # → -5
0 == False # → True
2 == True # → False
1 == True # → True
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 操作符: 比较操作符

# 比较大小
1 < 10  # → True
1 > 10  # → False
2 <= 2  # → True
2 >= 2  # → True

# 用 == 判断是否相等
1 == 1  # → True
2 == 1  # → False
3 = 2 # → 会报错, 因为 = 是表示赋值, == 才是判断是否相等

# 用 != 判断是否不等于
1 != 1  # → False
2 != 1  # → True

# 大小比较可以连起来!
1 < 2 < 3  # → True
2 < 3 < 2  # → False

# 当与None进行比较时, 不要用 ==
# 要用 is
# is 是用来比较两个变量是否指向同一个对象 
"etc" is None  # → False
None is None  # → True

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 操作符: 字符串的操作符

# 用加号连接字符串
"Hello " + "world!"  # → "Hello world!"
1
2

# 操作符: 列表的操作符

# 用 + 和空格来拼接列表
[1, 2, 3] + ['hello', 'python']  # → [1, 2, 3, 'hello', 'python']

# 用 * 来拷贝列表
[1, 2, 3]*3  # → [1, 2, 3, 1, 2, 3, 1, 2, 3]

# 列表也有逻辑操作
# ==、!=、<、<=、>、>=、in、not in
# 将两个列表中的元素逐个拿出来比较
# 遵循字符串比较相同的规则 -- 一旦决出胜负, 即刻停止, 不用再比较后面的元素
# in、not in 是用来判断元素是否在列表中的逻辑操作
a_list = [1, 2, 3]
b_list = [8]
c_list = [1, 4, 3]

a_list > b_list  # → False
a_list < b_list  # → False
a_list < c_list  # → True
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 操作符: 优先级

# 和学校学的算数一样, 乘除的优先级高于加减, 括号决定了计算的优先级
1 + 3 * 2  # → 7
(1 + 3) * 2  # → 8
1
2
3

# 容器

# 列表的操作

# 用列表(list)储存序列
li = []
# 创建列表时也可以同时赋给元素
other_li = [4, 5, 6]
# 用append在列表最后追加元素
li.append(1)    # li 现在是[1]
li.append(2)    # li 现在是[1, 2]
li.append(4)    # li 现在是[1, 2, 4]
li.append(3)    # li 现在是[1, 2, 4, 3]
# 用pop从列表尾部删除,并获得这个尾部的元素
li.pop()        # → 3 且 li 现在是[1, 2, 4]
# 把3再放回去
li.append(3)    # li 变回[1, 2, 4, 3]
# 列表存取跟数组一样
li[0]  # → 1
# 取出最后一个元素
li[-1]  # → 3
# 越界存取会造成IndexError
li[4]  # 抛出IndexError
# 列表可以切片
# 注意, 切片是从第1个参数指示的索引位置开始, 在第2个参数指示的索引位置之前就结束
# 所以, 下面的切片只取了第 1、2 个索引位置上的数
li[1:3]  # → [2, 4]
# 取尾
li[2:]  # → [4, 3]
# 取头
li[:3]  # → [1, 2, 4]
# 隔一个取一个, 也就是步长为 2. 注意, 原有列表的值不变
li[::2]   # →[1, 4]
# 倒序排列, 也就是步长为 -1. 注意, 原有列表的值不变
li[::-1]   # → [3, 4, 2, 1]

# 可以用三个参数的任何组合来构建切片
# li[始:终:步伐]

# 用del删除任何一个元素
del li[2]   # li 现在是 [1, 2, 3]
# 列表可以相加
# 注意: li 和 other_li的值都不变
li + other_li   # → [1, 2, 3, 4, 5, 6]

# 可以操作符 + 来拼接列表
li + other_li   # li现在是[1, 2, 3, 4, 5, 6]

# 也可以用 extend 拼接列表
li.extend(other_li)   # li现在是[1, 2, 3, 4, 5, 6]

# 用in测试列表是否包含值
1 in li   # → True

# 用len取列表长度
len(li)   # → 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 元组的操作

# 元组是不可改变的序列
tup = (1, 2, 3)
tup[0]   # → 1
tup[0] = 3  # 报错, TypeError, 因为元组不能被修改

# 列表允许的操作, 元组大部分都可以使用
len(tup)   # → 3
tup + (4, 5, 6)   # → (1, 2, 3, 4, 5, 6)
tup[:2]   # → (1, 2)
2 in tup   # → True

# 可以把元组合列表解包, 赋值给变量
a, b, c = (1, 2, 3)     # 现在a是1, b是2, c是3
# 元组周围的括号是可以省略的
d, e, f = 4, 5, 6
# 交换两个变量的值就这么简单
e, d = d, e     # 现在d是5, e是4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 字典的操作

# 用字典表达映射关系
empty_dict = {}
# 字典的初始化
filled_dict = {"one": 1, "two": 2, "three": 3}

# 用[]取值
filled_dict["one"]   # → 1


# 用 keys 可以获得该字典所有的键
# 因为 keys 返回的是一个可迭代对象, 所以在这里把结果包在 list 里
# 注意: 和列表不同, 字典的键的顺序是不定的, 你得到的结果可能和下面不一样
list(filled_dict.keys())   # → ["three", "two", "one"]


# 用 values 可以获得所有的值. 跟keys一样, 这里用list包起来, 顺序也可能不同
list(filled_dict.values())   # → [3, 2, 1]


# 用 in 测试一个字典是否包含一个键
"one" in filled_dict   # → True
1 in filled_dict   # → False

# 访问不存在的键会导致 KeyError
filled_dict["four"]   # KeyError
# 用 get 来避免 KeyError
filled_dict.get("one")   # → 1
filled_dict.get("four")   # → None
# 当键不存在的时候, get方法可以返回默认值
filled_dict.get("one", 4)   # → 1
filled_dict.get("four", 4)   # → 4

# setdefault 方法只有当键不存在的时候插入新值
filled_dict.setdefault("five", 5)  # filled_dict["five"]设为5
filled_dict.setdefault("five", 6)  # filled_dict["five"]还是5

# 字典赋值
filled_dict.update({"four":4}) # → {"one": 1, "two": 2, "three": 3, "four": 4}
filled_dict["four"] = 4  # 另一种赋值方法

# 用 del 删除键值对
del filled_dict["one"]  # 从 filled_dict 中把 "one": 1 的键值对删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 集合的操作

# 用set表达集合
empty_set = set()
# 初始化一个集合, 和字典的初始化相似
some_set = {1, 1, 2, 2, 3, 4}   # some_set现在是{1, 2, 3, 4}

# 可以把集合赋值给变量
filled_set = some_set

# 向集合添加元素
filled_set.add(5)   # filled_set现在是{1, 2, 3, 4, 5}

# 用 & 取集合的交集
other_set = {3, 4, 5, 6}
filled_set & other_set   # → {3, 4, 5}

# 用 | 取集合的并集
filled_set | other_set   # → {1, 2, 3, 4, 5, 6}

# 用 - 取集合的补集
{1, 2, 3, 4} - {2, 3, 5}   # → {1, 4}

# 用 in 测试集合中是否包含某元素
2 in filled_set   # → True
10 in filled_set   # → False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 输入输出

# 获取输入

# 获取用户输入的内容
a = input('请输入你的名字')
b = input('请输入你的年龄')
print("Welcome {name}! Your age is {age}.".format(name=a, age=b))
1
2
3
4

# 格式化输出

# print是内置的打印函数
print("Hello World!")  # → Hello World!
a = 'you'
b = 'me'
print(a, 'and', b, '.') # → you and me .
print(a, ' and ', b, '.', sep='', end='\n')  # → you and me.

# 用.format来格式化字符串
"{} can be {}".format("strings", "interpolated")

# 可以重复使用相同的参数
"我喜欢{0}, 爸爸也喜欢{0}, 妈妈喜欢{1}".format("苹果", "梨")
# → "我喜欢苹果, 爸爸也喜欢苹果, 妈妈喜欢梨"

# 如果不想数参数, 可以用关键字
"{name} wants to eat {food}".format(name="Bob", food="lasagna") 
# → "Bob wants to eat lasagna"

# 如果要输出多行字符串, 除了写一条一条语句之外, 还可以
message = """Hello, {name}
Sincerely, {me}"""
print (message.format(name = "Jake", me = "Sally"))
# 输出:
# Hello, Jake
# Sincerely, Sally

# 如果你的Python3程序也要在Python2.5以下环境运行
# 也可以用老式的格式化语法
# %s 表示string字符串, %d 表示digit数字, %f 表示float浮点数
"%s can be %s the %s way" % ("strings", "interpolated", "old")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 流程控制

# 流程控制: 判断

# 注意 "elif" 的写法, 它表示 else if

some_var = 5
if some_var > 10: #定义一个判断条件
    print("some_var 比 10 大")
elif some_var < 10:    # elif是可选的
    print("some_var 比 10 小")
else:                  # else也是可选的
    print("some_var 和 10 相等")
1
2
3
4
5
6
7
8
9

# 流程控制: 循环

# 有 2 种循环:
#    - for 循环
#    - while 循环


# for循环
# 用for循环遍历列表
for friends in ["李雷", "韩梅梅", "张华", "李萍"]:
    print("{}是我的朋友".format(friends))
# 打印结果:
"""
李雷是我的朋友
韩梅梅是我的朋友
张华是我的朋友
李萍是我的朋友
"""

# range 函数
# 用 range 函数生成列表, 用于for循环的迭代
for i in range(4):
    print(i)
# 打印结果:
"""
0
1
2
3
"""

for i in range(1,7,2):  # range(起始, 结尾, 步长), 注意, 切片在声明的结尾之前就结束了
    print(i)
# 打印结果:
"""
1
3
5
"""
# 注意, 上面的打印结果中没有 7, 因为在 7 之前就结束了


# while 循环
x = 0
while x < 4:
    print(x)
    x += 1  # x = x + 1 的简写
# 打印结果:
"""
0
1
2
3
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 流程控制: 异常

# 用 try/except 来处理“异常”, 也就是通常理解的“错误”
try:
    raise IndexError("This is an index error")  # 用raise抛出异常
except IndexError as e:
    pass    # pass是无操作, 但是应该在这里处理错误
except (TypeError, NameError):   # 可以同时处理不同类的错误
    pass
else:   # else 语句是可选的, 必须在所有的except之后
    print("All good!")   # 只有当try运行完没有错误的时候这句才会运行
1
2
3
4
5
6
7
8
9

# 可迭代对象

可迭代(iterable)的对象可以作为序列的对象, 比如上面的 range() 函数返回的对象就是可迭代的

filled_dict = {"one": 1, "two": 2, "three": 3}
our_iterable = filled_dict.keys()
print(our_iterable) # → dict_keys(['one', 'two', 'three']), 是一个可迭代对象

# 可迭代的对象可以遍历
for i in our_iterable:
    print(i)    # 打印 one, two, three

# 但是不可以随机访问
our_iterable[1]  # 报错, 抛出TypeError

# 可迭代对象知道怎么生成迭代器
our_iterator = iter(our_iterable)

# 迭代器是一个可以记住遍历的位置的对象
# 用 __next__ 可以取得下一个元素
our_iterator.__next__()  # → "one"
# 再一次调取__next__时会记得上一次的位置
our_iterator.__next__()  # → "two"
our_iterator.__next__()  # → "three"
# 当迭代器所有元素都取出后, 会抛出StopIteration
our_iterator.__next__() # 抛出StopIteration

# 可以用list一次取出迭代器所有的元素
list(filled_dict.keys())  # → Returns ["one", "two", "three"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 组织代码

# 组织代码: 函数

# 定义函数
def add(x, y):
    print("x is {} and y is {}".format(x, y))
    return x + y    # 用return语句返回



# 调用函数
add(5, 6)   # → 印出"x is 5 and y is 6"并且返回11

# 也可以用关键字参数来调用函数
add(y=6, x=5)   # 关键字参数可以用任何顺序
add(x=5, y=6)



# 可变参数
# 我们可以定义一个可变参数的函数, 即参数数量不用写死
def varargs(*args):
    return args

varargs(1, 2, 3)   # → (1, 2, 3)
varargs(1, 2, 3, 4)   # → (1, 2, 3, 4)

# 我们也可以定义一个关键字可变参数的函数
def keyword_args(**kwargs):
    return kwargs

keyword_args(big="foot", loch="ness")   # → {"big": "foot", "loch": "ness"}

# 这两种可变参数可以混着用
def all_the_args(*args, **kwargs):
    print(args)
    print(kwargs)

all_the_args(1, 2, a=3, b=4)
# 输出:
"""
(1, 2)
{'a': 3, 'b': 4}
"""

# 调用可变参数函数时可以做跟上面相反的, 用*展开序列, 用**展开字典
args = (1, 2, 3, 4)
kwargs = {"a": 3, "b": 4}
all_the_args(*args)   # 相当于 all_the_args(1, 2, 3, 4)
all_the_args(**kwargs)   # 相当于 all_the_args(a=3, b=4)
all_the_args(*args, **kwargs)   # 相当于 all_the_args(1, 2, 3, 4, a=3, b=4)



# 函数的作用域
x = 5

def setLocalX(num):
    x = num  # → 43, 这是局部作用域的 x, 和全局作用域的 x 不同
    print (x)  # → 43

def setGlobalX(num):
    global x  # 声明为为全局变量
    print (x) # → 5
    x = num # 全局作用域的 x 的赋值被修改
    print (x) # → 6

setLocalX(43)  # 输出 43
setGlobalX(6)  # 输出 5 6



# 函数在 Python 中是一等公民
def create_adder(x):
    def adder(y):
        return x + y
    return adder

add_10 = create_adder(10)
add_10(3)   # → 13



# 匿名函数
# 可以用 lambda 关键字来写匿名函数, 可以让函数的代码非常简洁
# 通常的函数写法:
def compare (x):
    return x >2
compare (3)   # → True
# lambada 匿名函数的写法:
compare = lambda x : x>2
compare(3)  # → True



# 内置的高阶函数
map(add_10, [1, 2, 3])   # → [11, 12, 13]
filter(lambda x: x > 5, [3, 4, 5, 6, 7])   # → [6, 7]

# 用列表推导式可以简化映射和过滤. 列表推导式的返回值是另一个列表
[add_10(i) for i in [1, 2, 3]]  # → [11, 12, 13]
[x for x in [3, 4, 5, 6, 7] if x > 5]   # → [6, 7]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

# 组织代码: 类

# 定义一个继承object的类
class Human(object):

    # 类的属性, 被所有此类的实例共用. 
    species = "H. sapiens"

    # 构造方法, 当有实例被初始化时, 就会被调用
    # 名字前后的双下划线, 表明这个属性或者方法对Python有特殊意义
    # 通常我们自己定义的名字不应该以下划线开头
    def __init__(self, name):
        # 将参数赋值给实例的属性
        self.name = name

    # 实例的方法, 第一个参数总是self, 就是这个实例对象
    def say(self, msg):
        return "{name}: {message}".format(name=self.name, message=msg)

    # 类方法, 被所有此类的实例共用. 第一个参数是这个类对象
    @classmethod
    def get_species(cls):
        return cls.species

    # 静态方法. 调用时没有实例或类的绑定
    @staticmethod
    def grunt():
        return "*grunt*"


# 构造一个实例
i = Human(name="Ian")
print(i.say("hi"))     # → "Ian: hi"

j = Human("Joel")
print(j.say("hello"))  # → "Joel: hello"

# 调用一个类方法
i.get_species()   # → "H. sapiens"

# 改一个共用的类属性
Human.species = "H. neanderthalensis"
i.get_species()   # → "H. neanderthalensis"
j.get_species()   # → "H. neanderthalensis"

# 调用静态方法
Human.grunt()   # → "*grunt*"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 组织代码: 模块

# 用import导入模块
import math  # 导入math数学模块, 才能调用开平方的 sqrt() 方法
print(math.sqrt(16))  # → 4.0

# 也可以从模块中导入指定的方法
from math import ceil, floor
print(ceil(3.7))  # → 4.0; 调用的时候, 只要写成 ceil(), 不用写成 math.ceil()
print(floor(3.7))   # → 3.0

# 你可以这样列出一个模块里所有的值
import math
dir(math)

# 可以导入一个模块中所有值
# 警告: 不建议这么做
from math import *

# 可以为模块设置别名
import math as m
math.sqrt(16) == m.sqrt(16)   # → True


# Python 模块的本质就是一个 Python 文件, import 就相当于导入这个文件
# 我们可以自己写一个 Python 文件, 然后将其作为模块导入
# 模块的名称就是文件的名字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 高阶用法: 生成器 & 装饰器

# 生成器(generators)
# 用生成器可以方便地写惰性运算
def double_numbers(iterable):
    for i in iterable:
        yield i + i

# 生成器只有在需要时才计算下一个值
# 它们每一次循环只生成一个值, 而不是把所有的值全部算好
# range的返回值也是一个生成器
# 不然一个1到900000000的列表会花很多时间和内存

# 如果你想用一个Python的关键字当作变量名, 可以加一个下划线来区分
range_ = range(1, 900000000)
# 当找到一个 >=30 的结果就会停
# 这意味着 `double_numbers` 不会生成大于30的数
for i in double_numbers(range_):
    print(i)
    if i >= 30:
        break



# 装饰器(decorators)
# 下面这个例子中, beg装饰say
# beg会先调用say. 如果返回的say_please为真, beg会改变返回的字符串
from functools import wraps

def beg(target_function):
    @wraps(target_function)
    def wrapper(*args, **kwargs):
        msg, say_please = target_function(*args, **kwargs)
        if say_please:
            return "{} {}".format(msg, "Please! I am poor :(")
        return msg

    return wrapper

@beg
def say(say_please=False):
    msg = "Can you buy me a beer?"
    return msg, say_please


print(say())  # Can you buy me a beer?
print(say(say_please=True))  # Can you buy me a beer? Please! I am poor :(
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45