目录
1 顺序结构
1.1 常量
约定俗成地,常量命名全部大写。
PI = 3.1415926
1.2 输入
x = input("Please input a number:")
这时x是一个字符串(str),若要获得一个数字,则需要int()。
x1 = int(x)
1.3 条件语句
注意冒号和严格的缩进。
money = int(input("Please input your money:"))
if money > 5000:
print("Buy a card.")
elif money > 1000:
print("Just wash your feet.")
else:
print("Just go ahead.")
1.4 for循环
可以迭代字符串或者range,以下范围都不包含n。
1.4.1 range(n)
表示从0到n。
1.4.2 range(m, n)
表示从m到n。
1.4.3 range(m, n, step)
表示从m到n,且步长为step。
1.5 代码占位
if a > 100:
pass
2 数据类型
2.1 基础数据类型
2.1.1 整数int
a = 10
2.1.2 浮点数float
a = 10.5
2.1.3 布尔类型bool
a = bool('1') # a == True
b = bool('') # b == False
c = bool(-1) # c == True
d = bool(0) # d == False
2.2 字符串string
2.2.1 长度
使用 len 函数。
s = "Hello world!"
print(len(s)) # 12
2.2.2 字符串格式化
可以使用%d(整数)、%s(字符串)、%f(浮点数)来占位。
name = kid
age = 10
s1 = "I am %s, I'm %d years old." % (name, age)
s2 = "I am {}, I'm {} years old.".format(name, age)
s3 = f"I am {name}, I'm {age} years old."
2.2.3 索引和切片
用索引的方式提取某个字符。
s = "I am Li Hua."
print(s[-1]) # -:reverse
切片提取字符时,前闭后开。
s = "I am Li Hua."
print(s[5:11]) # Li Hua
print(s[8:]) # Hua.
print(s[:4]) # I am
print(s[-2:-8:-1]) # auH iL
2.2.4 大小写切换
首字母大写使用 capitalize 函数。
s = "python"
s1 = s.capitalize()
print(s1) # Python
全部英文单词首字母大写使用 title 函数。
s = "I have a dream!"
s1 = s.title()
print(s1) # I Have A Dream!
全部变成小写使用 lower 函数。
s = "I Have A Dream!"
s1 = s.lower()
print(s1) # i have a dream!
全部变成大写使用 upper 函数,值得注意的是, lower 函数不支持部分希腊字母,但是 upper 函数支持,所以 upper 函数的使用频率更高。
s = "I Have A Dream!"
s1 = s.upper()
print(s1) # I HAVE A DREAM!
比如网页验证码不区分大小写,就可以使用此函数。
verify_code = "xAd1"
user_input = input("Please input the verify code:")
if verify_code.upper() == user_input.upper()
print("Right!")
else
print("Wrong!")
2.2.5 切割和替换
去除字符串两端的空格、制表符或换行符可以使用 strip 函数。
s = " I Have A Dream! "
s1 = s.strip()
print(s1) # I Have A Dream!
替换可以用 replace 函数,格式是 replace(str1, str2[, max]) 。其中如果指定max,则表示替换的最多次数。如果要去掉所有str1,则str2等于空字符串。
s = " I Have A Dream! "
s1 = s.replace(" ", "")
print(s1) # IHaveADream!
字符串切割使用 split 函数,且会返回一个列表。
s = "python_java_c_c#_javascript"
lst = s.split("_")
print(lst) # lst is a list, composed of strings.
2.2.6 查找与判断
查找可以使用 find 函数,并返回所找内容的位置。若查找不到,则返回 -1 。
s = "Hello world!"
ret1 = s.find("world")
ret2 = s.find("word")
print(ret1) # 6
print(ret2) # -1
查找还可以使用 index 函数,但是与 find 函数不同的是,当未查找到时,程序报错。
如果要判断一个子串是否存在于一个字符串,则可以使用 in 或 not in 。
s = "Hello world!"
print("word" in s) # False
print("world" in s) # True
print("word" not in s) # True
如果要判断字符串是否以某一字符开始,可以使用 startswith 函数。
s = "Hello world!"
print(s.startswith("H")) # True
print(s.startswith("h")) # False
判断是否为整数,使用 isdigit 函数。
s = "114514"
print(s.isdigit()) # True
2.2.7 字符串的连接
将列表内的字符串连接为一个字符串,使用 join 函数。
lst = ["python", "c", "c#", "javascript"]
s = "_".join(lst)
print(s) # python_c_c#_javascript
2.3 列表list
在python中用中括号([])来表示一个列表,其中元素用逗号(,)隔开。
2.3.1 特性
列表的元素可以是任意数据类型。像字符串一样,列表也可以进行索引和切片操作。但值得注意的是,如果索引超过范围就会报错。可以用for循环一项一项遍历。可以使用 len 来求出列表的长度。
2.3.2 增删改查
增添内容使用 append 函数,将放在列表的最后。
lst = []
lst.append("python")
lst.append("c")
lst.append("java")
print(lst) # ['python', 'c', 'java']
插入内容使用 insert 函数,可以指定插入的位置。
lst = ["python", "c", "javascript"]
lst.insert(2, "c#")
print(lst) # ['python', 'c', 'c#', 'javascript']
合并两个列表使用 extend 函数。
lst = ["python", "c", "javascript"]
lst.extend(["c#", "java"])
print(lst) # ['python', 'c', 'javascript', 'c#', 'java']
删除可以使用 pop 函数,需要给出索引,会返回删除的元素。
lst = ["python", "c", "javascript"]
ret = lst.pop(2)
print(lst) # ['python', 'c']
print(ret) # javascript
删除也可以使用 remove 函数,此时直接给出元素即可,若同时存在多个相同的给出元素,则删除第一个。值得注意的是,使用remove后,列表后方所有项都会向前移动一位,此时若循环遍历,则会有部分元素被忽略。
lst = ["python", "c", "javascript"]
lst.remove("c")
print(lst) # ['python', 'javascript']
2.3.3 排序
使用 sort 函数。若在加上 reverse=True ,则表示降序排序。
lst = [9, 3, 7, 5, 1]
lst.sort()
print(lst) # [1, 3, 5, 7, 9]
lst.sort(reverse=True)
print(lst) # [9, 7, 5, 3, 1]
2.3.4 列表嵌套
lst = [[1, 3, 2], 'world', ['hello', [1, 3], 'histology']]
print(lst[2][1][1]) # 3
2.3.5 解构(解包)
列表和元组两种数据类型都可以进行此操作。需要注意的是,前面的元素个数一定要与列表的元素个数相同,否则报错。
lst = [3, 2]
a, b = lst
print(a) # 3
print(b) # 2
2.4 元组tuple
相当于不可变的列表,使用小括号表示(())。若尝试修改,则会报错。当元组只有一个元素时,定义时需要多加一个逗号,否则括号将被视为优先级。
t1 = ("haha", )
t2 = ("haha")
print(t1) # ('haha')
print(t2) # 'haha'
2.5 集合set
乱序地存放一堆元素,用花括号({})表示。元素必须是可以哈希的值,即不能存储列表、字典和集合。
2.5.1 创建空集合
不能直接使用一堆花括号,那会创建一个字典,但是可以用 set() 。
s = set()
2.5.2 增加、删除元素
s = set()
s.add('python')
s.add('c')
s.remove('python')
print(s) # ('c')
2.5.3 集合的运算
取交集可以用 & 或 intersection 函数。取并集可以用 | 或 union 函数。取差集可以用减号(–)。
s1 = {"python", "java"}
s2 = {"python", "c#"}
print(s1 & s2) # {'python'}
print(s1 | s2) # {'python', 'java', 'c#'}
print(s1 – s2) # {'java'}
集合可以用于去除重复,但是结果是无序的。
lst = [1, 3, 3, 7, 1, 5]
print(list(set(lst))) # [1, 7, 5, 3]
2.6 字典
以键值对的形式存放,以花括号({key: value})表示。其中,key必须可哈希,但是value可以是任何值。
2.6.1 增删改查
设置默认值可以用 setdefault 函数,若字典中已经有给定的key,则赋值,否则创建新值。
dic = dict()
dic['jay'] = "chou"
dic.setdefault['jay', "kunling"]
dic.setdefault['tom', "soup"]
print(dic['jay']) # chou
print(dic['tom']) # soup
删除值可以使用 pop 函数,或 del 函数。pop函数需要给出key值。
dic = {'jay': "chou", 'tom': "soup"}
dic.pop['jay']
del dic['jay'] # not quite often used.
查询字典值可以直接索引,也可以用 get 函数。但是值得注意的是,key不存在时,用索引则程序报错,用get函数则返回None。
dic = {'jay': "chou", 'tom': "soup"}
print(dic['jay001']) # Error!
print(dic.get('jay001')) # None
2.6.2 循环和嵌套
可以直接用for循环,直接拿到key。
dic = {'a': 1, 'b': 2, 'c': 3}
for key in dic
print(key) # a b c
如果要一次性获取所有key或者value,可以使用 keys 和 values 函数。
dic = {'a': 1, 'b': 2, 'c': 3}
print(list(dic.keys()))
print(list(dic.values()))
如果要直接拿到字典的所有key和value ,则可以使用 items 函数。
dic = {'a': 1, 'b': 2, 'c': 3}
print(dic.items) # [('a', 1), ('b', 2), ('c', 3)]
当然,这个结果以元组的形式呈现,非常臃肿,因此可以考虑 拆包 的形式直接获取key和value的值。
dic = {'a': 1, 'b': 2, 'c': 3}
for k, v in dic.items():
print(k, v)
# a 1
# b 2
# c 3
嵌套的形式与列表相同,直接使用多个中括号([])即可。
2.6.3 循环删除
与列表相同,字典在循环中删除某项,也会导致字典大小发生改变,从而报错。因此需要临时建立一个新列表,储存需要删除的key。
dic = {'a': 1, 'b': 2, 'c': 3, 'aa': 4}
temp=[]
for key in dic
if key.startswith("a")
temp.append(key)
for t in temp
dic.pop(t)
print(dic) # {'b': 2, 'c': 3}
2.7 字节bytes
使用GBK、utf等字符集编码,形式是 b’code’ ,其中单引号内的内容就是编码。
使用 encode 和 decode 函数进行编码和解码。
s = "周杰伦"
print(s.encode("gbk"))
# b'\xd6\xdc\xbd\xdc\xc2\xd7'
print(s.encode("utf-8"))
# b'\xe5\x91\xa8\xe6\x9d\xb0\xe4\xbc\xa6'
解码后再编码可以实现两种编码的转换。
bs1 = b'\xd6\xdc\xbd\xdc\xc2\xd7'
s = bs.decode
bs2 = s.encode
2.8 运算符
2.8.1 算数运算
求余数使用百分号(%),只计算整数的除法用(//)。
2.8.2 比较运算
不等于是(!=)。
2.8.3 赋值运算
可以使用+=、-=、*=、/=来运算。
a, b = 1, 1
a = a + 1
b += 1 # equivalent.
2.8.4 逻辑运算
并且 and 、或者 or 、否定 not 。
优先顺序:括号> not > and > or。
2.8.5 成员运算
使用 in 。
2.9 文件操作
2.9.1 读取文件
语法为 open(“path”, mode=“”, encoding=“”) 。其中路径分为绝对路径和相对路径。使用相对路径时,使用两个句点(…/)表示上一级目录。而读取文件的模式mode为r(read)。使用 read 函数可以将文件的所有内容全部读取。
f = open("../resource.txt", mode="r",encoding="utf-8")
content = f.read()
print(content)
使用 readline 函数可以读取一行,且包括换行符,再使用readline函数时,将会读取下一行。由于包括了换行符,所以读取的时候可以先使用 strip 函数将多余的换行符去除。这个函数最常用,因为它不会将文件一次性全部打开,避免内存溢出。
f = open("input.txt", mode="r", encoding="utf-8")
line = f.readline().strip()
print(line)
如果要将所有内容读取并且储存到一个列表中,则使用 readlines 函数。
f = open("input.txt", mode="r", encoding="utf-8")
lines = f.readlines()
print(lines) # a list made up of string.
最关键的读取方式为直接for循环遍历文件的所有行。
f = open("input.txt", mode="r", encoding="utf-8")
for line in f: # read every line in the file.
print(line)
2.9.2 写入文件
写入文件的模式为“w”(write),若写入的文件不存在,则会创建一个文件。每次open都会清空文件中的内容。写入文件的函数是 write 函数,且此函数输入后需要自行添加换行符。最好在进行文件操作后关闭文件,使用 close 函数。
f = open("output", mode="w", encoding="utf-8")
f.write("Hello world!")
f.close()
追加写入文件的模式为 “a”(append)。此模式下,open操作不会清空文件。
2.9.3 使用with来打开文件
在 with (上下文)的条件下,可以省略使用close来关闭函数,故此方法最常用。
with open("output.txt", mode="w", encoding="utf-8") as f:
for line in f:
print(line.strip())
2.9.4 非文本文件
非文本文件的操作时,模式mode需要加上“b”,写为“rb”“wb”等。可以用此完成文件复制。
with open("picture1.jpg", mode="rb") as f1, \
open("../picture2.jpg", mode="wb") as f2:
for line in f1:
f2.write(line)
2.9.5 修改文件
无法对一个文件同时进行读取和写入,因此需要创建一个副本,写入完成后再将副本覆盖原文件。此时需要引入 os 库,调用其中的 remove 和 rename 函数用于删除和重命名。
import os
with open("input.txt", mode="r", encoding="utf-8") as f1, \
open("input_copy.txt", mode="w", encoding="utf-8") as f2:
for line in f1:
line = line.strip()
if line.startswith("a"):
line = line.replace("a", "b")
f2.write(line)
f2.write("\n")
os.remove("input.txt")
os.rename("input_copy.txt", "input.txt")
3 函数
3.1 参数
3.1.1 实参
实参用三种传递方式:位置参数、关键字参数、混合参数。其中混合参数中需要先输入位置参数,再输入关键字参数。
def info(name, age, hobby):
pass
info("Octo", 18, "Sleep")
info(age=18, name="Octo", hobby="Sleep")
info("Octo", hobby="Sleep", age=18) # the three are equivalent.
3.1.2 形参
在设置时,可以设置一个默认值,如果实参不传递信息,则默认值生效。值得注意点是,若默认值参数和位置参数同时存在,则需要将默认值参数放后面(顺序:位置 > 默认值)。
def info(name, age, hobby="Sleep"):
pass
info("Octo", 18, "Sleep")
info(age=18, name="Octo")
info("Octo", hobby="Sleep", age=18) # the three are equivalent.
如果要同时传入多个参数,且不确定参数的个数,可以使用动态传参,用星号(*)表示,形式为 *args。值得注意的是,星号接收到的值被存放在元组内。
def eat(*food):
print(food)
eat("rice", "noodles")
# ('rice', 'noodles')
eat("rice")
# ('rice')
eat("noodles", "soup", "fruit")
# ('noodles', 'soup', 'fruit')
除此之外,动态传参还可以表示为 **kwargs ,这时这种传参是关键字传参,以字典形式储存。
def eat(**food):
print(food)
eat(main="rice", dessert="salad", soup="fotiaoqiang")
# {'main':'rice', 'dessert':'salad', 'soup':'fotiaoqiang'}
综合考虑四种传参,为了避免数据被错误传递,应该有这样的顺序:
位置 > *args > 默认值 > **kwargs
def func(*args, **kwargs):
print(args, kwargs)
func() # () {}
func(1) # (1, ) {}
func(1, 2, 3, 4, a=2) # (1, 2, 3, 4) {'a':2}
func(1, 2, 3, c=4, d=6) # (1, 2, 3) {'c':4, 'd':6}
如果星号(*)在实参位置,则可以将列表打散成位置参数进行传递。如果双星号(**)在实参,则可以把字典转化为关键字参数进行传递。
def func(*args):
print(args)
stu_lst = ['a', 'b', 'c', 'd']
func(*stu_lst)
# ('a', 'b', 'c', 'd')
3.2 返回值
返回值如果未声明,则为 None 。如果写了return但是并未在之后加任何值,则同样返回None,但是函数会立即停止,而不执行之后的代码。如果返回值有多个,则以元组的形式返回。
3.3 内置函数
即python已经写好,能直接使用的函数。
3.3.1 进制转化 bin、oct、hex
bin、oct、hex 分别是2、8、16进制转化。int可以将其他进制数变为十进制。
a = 0b10010
print(int(a)) # 18
3.3.2 与数字相关 sum、max、min
sum、max、min 分别是求和、最大值、最小值。
3.3.3 字符串 format
格式化使用 format ,进制转化时需要调整第二个参数内的字母。
字母 | 进制 |
---|---|
b | 2 |
o | 8 |
x | 16 |
如果需要补齐指定n位数,则在字母前加上 0n 。
a = 18
print(format(a, "08b")) # 00010010
3.3.3 Unicode码位
要寻找字符的码位,则使用 ord 函数。
a = "中"
print(ord(a)) # 20013
将码位转化为字符,则使用 chr 函数。
print(chr(20013)) # 中
3.3.4 相关内置函数
3.3.4.1 all、any
all 函数相当于and,any 函数相当于or。
lst = [0, "cook", '']
print(all(lst)) # False
print(any(lst)) # True
3.3.4.2 获取列表索引和内容 enumerate
enumerate 函数可以取得列表的索引和内容,并以元组形式返回。
lst = ["rice", "noodle", "fruit"]
for item in enumerate(lst):
print(item)
# (0, 'rice')
# (1, 'noodle')
# (2, 'fruit')
for index, item in enumerate(lst):
print(index, item)
# 0 rice
# 1 noodle
# 2 fruit
3.3.4.3 串联不同列表 zip
可将不同列表的信息串联起来,并以迭代器的形式储存,且迭代器的每一项是一个元组。
name = ["KeLi", "WenDi", "FuFu"]
age = [5, 2000, 3000]
hobby = ["Bomb", "Beer", "Drama"]
result = zip(name, age, hobby)
for item in result:
print(item)
"""
('KeLi', 5, 'Bomb')
('WneDi', 2000, 'Beer')
('FuFu', 3000, 'Drama')
"""
如果要将结果储存到一个列表,则使用 list 自动转化为列表。
name = ["KeLi", "WenDi", "FuFu"]
age = [5, 2000, 3000]
hobby = ["Bomb", "Beer", "Drama"]
result = zip(name, age, hobby)
lst = list(result)
print(lst)
# [('KeLi', 5, 'Bomb'), ('WneDi', 2000, 'Beer'), ('FuFu', 3000, 'Drama')]
3.3.5 帮助函数help、dir
help、dir 函数分别可以查看数据类型的源码、能进行的操作。
s = "abcde"
help(str)
dir(s)
3.3.6 作用域相关 locals、globals
locals 用于查看当前作用域的变量, globals 用于查看全局变量。
3.3.7 排序 sorted
格式如下。
sorted(__iterable, key, reverse)
参数 | 含义 | 要求 |
---|---|---|
__iterable | 排序对象 | 可迭代 |
key | 排序规则 | 函数 |
reverse | 升序降序 | bool |
def func(x):
return len(x)
name = ["DiLuke", "KeLi", "WenDi"]
result = sorted(name, key=func)
print(result) # ['Keli', 'WenDi', 'DiLuke']
可以与lambda表达式一起使用。详见3.11 匿名函数。
name = ["DiLuke", "KeLi", "WenDi"]
result = sorted(name, key=lambda x: len(x))
print(result) # ['Keli', 'WenDi', 'DiLuke']
也可以对字典进行排序。
lst = [
{"id": 1, "name": "ZhongLi", "age": 9999}
{"id": 2, "name": "WenDi", "age": 2000}
{"id": 3, "name": "KeLi", "age": 5}
]
result = sorted(lst, lambda d: d['age'])
print(result)
"""
[
{"id": 3, "name": "KeLi", "age": 5},
{"id": 2, "name": "WenDi", "age": 2000},
{"id": 1, "name": "ZhongLi", "age": 9999}
]
"""
3.3.8 筛选 filter
filter函数可以筛选出列表中某些元素,并以生成器的形式返回,详见3.10生成器。格式如下。
filter(function, __iterable)
参数 | 含义 | 条件 |
---|---|---|
function | 筛选条件 | 函数 |
__iterable | 被筛选变量 | 可迭代 |
lst = ["NaXida", "NaWeiaite", "Ying"]
f = filter(lambda x: x.startswith("N"), lst)
print(list(f)) # ['NaXida', 'NaWeilaite']
3.3.9 映射 map
map函数可以对所有元素进行相同处理,并以生成器的形式返回,详见3.10生成器。格式如下。
map(__func, __iterable)
参数 | 含义 | 条件 |
---|---|---|
__func | 对元素进行的操作 | 函数 |
__iterable | 被操作变量 | 可迭代 |
lst = [1, 2, 3, 4, 5]
r = map(lambda x: x ** 2, lst)
print(list(r)) # [1, 4, 9, 16, 25]
3.4 作用域
分为全局变量和局部变量,局部变量即在函数内定义的变量。想要在函数外引用变量,只能使用return。
3.5 函数嵌套
必须声明的一点:
函数可以作为返回值进行返回。
函数嵌套指在函数内再声明一个函数,此嵌套的函数同样不能在外面使用。如果要使用,只能通过直接返回这个函数(returm后可以跟一个函数)。
def func():
def inner():
print(123)
return inner
b1 = func() # now b1 is the function innner.
b1()
值得注意的是,在以上例子,打印b1和inner函数的地址,会发现两者相同,说明此时b1就是inner函数。
同样地,传参时,参数也可以是一个函数。当一个函数以参数的形式在另一个函数中执行,这叫做代理模式。
def func(an):
an()
def target():
print("I'm a target.")
func(target) # I'm a target.
3.6 函数与全局变量
如果要在函数内修改全局变量,则需要使用 global 。
a = 10
b = 10
def func1():
a = 10
def func2():
global b
b = 20
print(a, b) # 10 20
以上例子中,在func1中的a = 10实际上是创建了局部变量a,并赋值10,而并非修改了全局变量a。
如果要在函数内找函数以外的局部变量,则需要使用 nonlocal 。此时会逐层向外寻找变量,但不包括全局变量。如果未找到此变量,则报错。
def func():
a = 10
b = 20
def func2():
nonlocal a
a = 20
b = 20
func2()
print(a, b) # 20 10
3.7 闭包
当将一个函数赋值给一个变量时,函数内的变量就会常驻于内存中,对其做出的改变将会被保存。本质如下。
内层函数对外层函数的局部变量的使用。
此时的内层函数被称为闭包函数。
def func():
a = 10
def inner():
a += 10
return a
return inner
ret = func()
r1 = ret()
print(r1) # 11
r2 = ret()
print(r2) # 12
上面的例子中,a被封闭在func中,外部无法修改a的值,除非使用ret才行。这样便可以达到a如同一个全局变量的效果,且a无法被修改,除非使用指定的函数。这样便可以保护a。
3.8 装饰器
3.8.1 定义
装饰器本质上是一个闭包,作用如下。
在不改变原有函数调用的情况下,给函数增加新的功能。
形式如下。
def wrapper(fn):
def inner():
# before the function...
fn()
# after the function...
return inner
表示方式是先定义一个闭包函数wrapper(),之后在需要装饰的函数前加 @wrapper ,也可以使用赋值的形式。
def add_cheater(game):
def inner():
print("Cheater started.")
game()
print("Cheater stopped.")
return inner
@add_cheater
def play_lol():
print("Legends never die!")
def play_genshin():
print("Towards stars and gulfs!")
play_lol()
"""
Cheater started!
Legends never die!
Cheater stopped.
"""
play_genshin()
"""
Towards stars and gulfs!
"""
play_genshin = add_cheater(play_genshin)
play_genshin()
"""
Cheater started!
Towards stars and gulfs!
Cheater stopped.
"""
3.8.2 被装饰函数的参数
如果需要传递参数,则wrapper()需要做出改变,需要添加能接受任意数量参数的 *args 和 **kwargs 。
def wrapper(fn):
def inner(*args, **kwargs):
# before the function...
fn(*args, **kwargs)
# after the function...
return inner # don't add brackets!
3.8.3 被装饰函数的返回值
被装饰函数有返回值时,装饰器内也应该有返回。故通用装饰器写法如下。
def wrapper(fn):
def inner(*args, **kwargs):
# before the function...
ret = fn(*args, **kwargs)
# after the function...
return ret
return inner
@wrapper
def target():
pass
target() # => inner()
3.8.4 多个装饰器
多个装饰器同时存在时,先引用的装饰器在更外层。
def wrapper1(fn):
def inner(*args, **kwargs):
print("wrapper1 started.")
ret = fn(*args, **kwargs)
print("wrapper1 ended.")
return ret
return inner
def wrapper2(fn):
def inner(*args, **kwargs):
print("wrapper2 started.")
ret = fn(*args, **kwargs)
print("wrapper2 ended.")
return ret
return inner
@wrapper1
@wrapper2
def target():
print("I'm the target.")
target() # => inner()
"""
wrapper1 started.
wrapper2 started.
I'm the target.
wrapper2 ended.
wrapper1 ended.
"""
# order: w1 -> w2 -> t -> w2 -> w1
3.9 迭代器
3.9.1 迭代器使用
获取迭代器的两种方案
- iter() 内置函数可以直接拿到迭代器
- __iter()__ 特殊方法
如果使用迭代器超过可以迭代的次数,则报错。
同样地,进行一次迭代也有两种方案。
- next
- __next__
s = "Never gonna give you up~"
it1 = iter(s)
it2 = s.__iter__()
print(next(it1)) # N
print(next(it1)) # e
print(it2.__next__()) # N
print(it2.__next__()) # e
由此可以模拟for循环工作原理。
s = "Mamba"
it = iter(s)
while 1:
try:
data = next(it)
print(data)
except StopIteration:
break
print("Finished!")
"""
M
a
m
b
a
Finished!
"""
以上例子中,try表示尝试运行代码,如果报错,则进入except后的内容,StopIteration表示错误类型为迭代器超过范围。
3.9.2 迭代器特性
- 本身可被迭代;
- 只能向前,不能反复;
- 节省内存;
- 惰性机制(只有在访问时才会移动)。
3.9.3 迭代器表达式
作用如下。
简化代码。
值得注意的是,由于元组不可修改,故元组没有推导式。如果出现了小括号内有表达式的情况,那是生成器表达式。
3.9.3.1 列表推导式
格式:[数据 for循环 if判断]
lst1 = [i for i in range(10) if i % 2 == 1]
print(lst) # [1, 3, 5, 7, 9]
lst2 = [f"item{i}" for i in range(3)]
print(lst2) # ['item0', 'item1', 'item2']
name = ["kevin", "tony", "tom"]
lst3 = [item.upper() for item in name]
print(lst3) # ['KEVIN', 'TONY', 'TOM']
3.9.3.2 集合推导式
格式:{数据 for循环 if判断}
与列表推导式用法相同。
3.9.3.3 字典推导式
格式:{k:v for循环 if判断}
lst = ["C", "C++", "Java"]
dic = {i: lst[i] for i in len(lst)}
# {0: 'C', 1: 'C++', 2: 'Java'}
3.10 生成器
3.10.1 特性
生成器的本质就是迭代器。
创建生成器函数的方案:
- 生成器函数;
- 生成器表达式。
3.10.2 生成器函数
生成器函数中有一个关键字 yield 。需要注意的是,yield只有在执行到next时才会返回数据。
生成器函数执行的时候,得到的是生成器,而不会执行函数。
def func():
print(123456)
yield 999
ret = func()
print(ret.__next__()) # 123456 999
print(ret.__next__()) # Error!
可以用yield实现函数分段执行,通过__next__()来执行下一段。
def func():
print(123)
yield 999
print(456)
yield 999
ret = func()
print(ret.__next__()) # 123 999
print(ret.__next__()) # 456 999
3.10.3 生成器表达式
格式:(数据 for循环 if判断)
gen = (i**2 for i in range(5))
for item in gen:
print(item)
lst = list(gen)
print(lst) # []
# 0 1 4 9 16
值得注意的是,生成器的数据是一次性的。如上面的例子中,for循环已经拿空了生成器,所以后面的lst只能得到一个空列表。
3.11 匿名函数
可以认为是一个 lambda表达式。 可以简洁地创建一个函数,且无需声明其名字。
fn = lambda a, b: a + b
print(fn(13, 12)) # 25
它常与map、sorted等内置函数一起使用。