Python基础学习笔记(12)生成器 列表推导式 内置函数Ⅰ
Python基础学习(12)生成器 列表推导式 内置函数Ⅰ
一、今日内容大纲
- 生成器
- 列表推导式
- 内置函数Ⅰ
二、生成器 generator
-
生成器的概念
生成器和迭代器可以看作一种,生成器本质就是迭代器。两者唯一的区别是:生成器是我们自己利用 Python 代码构建的数据结构,而迭代器是 Python 提供的,或者利用 iter() 转化而来的。
-
获取生成器的方式
- 生成器函数
- 生成器表达式
- Python 内置函数或者模块提供(其实1,3两种本质上差不多,都是通过函数的形式生成,只不过1是自己写的生成器函数,3是python提供的生成器函数而已)
-
生成器函数
以下是我们平时使用的函数基本形式:
# 这是我们平时的函数 def func(): print(111) print(222) return 3 print(func())
这是利用 yield 构建的生成器函数:
# 这是生成器函数 def func(): print(111) # line 26: next(ret) print(222) # line 26: next(ret) yield 3 # line 26: next(ret) # 只有在下次 next(ret) 执行时才运行上次 yield 下面的代码 print(333) # line 27: next(ret) yield 4 # line 27: next(ret) # func() # 无法运行 ret = func() print(ret) # <generator object func at 0x000002072E771FC0> print(next(ret)) # 3 print(next(ret)) # 4 print(next(ret)) # StopIteration
可以看到,yield 和 return 分别构成生成器函数和函数,两者具有以下区别:
- return:函数只存在一个 return 结束函数,并且给函数的执行者返回值
- yield :只要函数中有 yield 那么它就是生成器函数而不是函数,生成器函数中可以存在多个 yield,yield 不会结束生成器函数,一个 yield 对应一个 next()。
# Example 1: (这样使用其实没有意义) def func(): print(111) return 111 yield 222 # 只要有yield就是生成器函数 ret = func() print(ret) # <generator object func at 0x00000229C76E1FC0> # print(next(ret)) # StopIteration: 111
# Example 2: 买包子 # 先做再吃:可迭代对象 def func(): l1 = [] for i in range(1, 5001): l1.append(f'{i}号包子') return l1 ret = func() print(ret) # 吃一个做一个:迭代器 def gen_func(): for i in range(1, 5001): yield f'{i}号包子' ret = gen_func() for i in range(200): print(next(ret))
-
yield from
下面通过代码的形式对比一下 yield 和 yield from 的用法:
# yield 情况 def func(): l1 = [1, 2, 3, 4, 5] yield l1 ret = func() print(next(ret)) # [1, 2, 3, 4, 5] # yield from 情况:将列表变成迭代器返回 def func(): l1 = [1, 2, 3, 4, 5] yield from l1 ret = func() print(next(ret)) # 1 print(next(ret)) # 2 print(next(ret)) # 3 print(next(ret)) # 4 print(next(ret)) # 5 # print(next(ret)) # StopIteration
# Exercise 3: 两个yield from 是顺序执行的 def func(): lis1 = ['weilong', 'laobinggun', 'beibingyang', 'niuyangpei'] lis2 = ['mantou', 'huajuan', 'doubao', 'dabing'] yield from lis1 yield from lis2 g = func() for i in range(8): print(next(g),end=' ') # result: weilong laobinggun beibingyang niuyangpei mantou huajuan doubao dabing
三、列表推导式和生成器表达式
-
列表推导式的概念
利用已知的方法构建一个含有元素 1-10 的列表:
# 构建一个1-10的列表 list = [] for i in range(1, 11): list.append(i) print(list)
而利用列表推导式,可以仅用一行代码完成一个相对复杂且有规律的列表的构建:
l1 = [i for i in range(1, 11)]
-
列表推导式种类
- 循环模式:
[variable(after processing) for variable in iterable]
- 筛选模式:
[variable(after processing) for variable in iterable if condition]
# Example 1: PLS use the cycle mode # 将10以内所有整数的平方写入列表 list = [i**2 for i in range(1, 11)] # 100以内所有的偶数写入列表 list = [i for i in range(0, 100, 2)] # 从python1期到python100期写入列表 list = [f'Python{i}期' for i in range(1, 101)] # Example 2: PLS use the filter mode # 30以内被3整除的数 list = [i for i in range(1, 31) if i % 3 == 0] # 过滤掉长度小于3的字符串列表,并将剩下的转换为大写字母 l1 = ['barry', 'ab', 'alex', 'wusir', 'xo'] list = [str.upper() for str in l1 if len(str) >= 3] print(list) # 找到嵌套列表中名字含有两个'e'的所有名字 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] list = [str for l1 in names for str in l1 if str.count('e') >= 2] print(list) # Example 3:构建一个列表:[2,3,4,5,6,7,8,9,10,'J','Q','K','A'] l1 = [i for i in range(2, 11)] + list('JQKA') print(l1)
- 循环模式:
-
生成器推导式(生成器表达式)
将列表推导式最外层的'[]'替换为'()'就是生成器推导式:
# 与列表推导式的写法几乎一模一样 list = [i for i in range(1, 11)] # 列表推导式 generator = (i for i in range(1, 11)) # 生成器推导式 print(generator) # <generator object <genexpr> at 0x00000156A5CCD0F8> for i in generator: # generator 和 iterator 也是可以像可迭代对象一样for循环输出的 print(i)
-
列表推导式的特点
- 只能构建比较复杂且有规律的列表
- 超过三层循环才能构建成功的,不建议使用列表推导式
- 无法 debug
-
列表推导式和生成器表达式的区别
写法上,列表推导式为
[]
,生成器表达式为()
;本质上,列表推导式属于
iterable
,生成器表达式属于iterator
-
其他类型推导式(了解)
-
字典推导式
lst1 = ['jay', 'jj', 'meet'] lst2 = ['周杰伦', '林俊杰', '元宝'] dic = {lst2[i]: lst1[i] for i in range(len(lst1))}
-
集合推导式
print({i for i in range(1, 11)})
-
四、内置函数Ⅰ
Python 一共提供了68个内置函数,我们今天仅一带而过部分不是特别重要的内置函数:
-
eval()
:全称 Evaluate,剥去字符串外衣运算内部的代码,返回去除引号的代码计算结果,尽量不要使用,容易引起病毒。网络传输、input 输入、Sql 注入等等情况绝对不可以使用!s1 = '1 + 3' print(s1) # 1 + 3 print(eval(s1)) # 4
-
exec()
:全称 Execute,与eval()
几乎一样,不同之处在于它用来于代码流。msg = """ for i in range(10): print(i) """ exec(msg) # print(eval(msg)) # SyntaxError: invalid syntax
-
hash()
:获取一个对象(可 hash 对象包括int str bool tuple
等)的哈希值。print(hash('123')) # 8755506514922830437
-
help()
:帮助。print(help('das')) print(help(str)) print(help(str.upper))
-
callable()
:检查一个对象是否可以调用,根据情况返回布尔值。def func(): pass i = 1 print(callable(i), callable(func)) # False True
-
int() float()
:将字符串或数字转换为整数或浮点数(直接略去小数点)。 -
complex(real, imag)
:创建一个值为real + imag * j
的复数,如果输入字符串形式,无需指定第二个元素。print(complex(1,2)) # (1+2j) print(complex('1-2j')) # (1-2j)
-
bin() oct() hex()
:全称 binary octal hexadecimal,将十进制分别转化为二、八、十六进制的字符串并返回。print(bin(10), type(bin(10))) # 0b1010 <class 'str'> print(oct(10), type(oct(10))) # 0o12 <class 'str'> print(hex(10), type(hex(10))) # 0xa <class 'str'>
-
divmod(x, y)
:全称 division modulo,返回一个包含商和余数的元组(x // y, x % y)
。round()
:保留浮点数的小数位数,默认保留整数。pow()
:全称 power,返回x ** y
,传入三个参数时的返回结果为(x ** y) % z
。print(divmod(7,2)) # (3, 1) print(round(7/3,2)) # 2.33 print(round(7/3)) # 2 print(round(3.32567,3)) # 3.326 print(pow(2,3)) # 两个参数为2**3次幂 print(pow(2,3,3)) # 三个参数为2**3次幂,对3取余。
-
bytes()
:用于不同编码之间的转化。s = '你好' bs = s.encode('utf-8') print(bs) s1 = bs.decode('utf-8') print(s1) bs = bytes(s,encoding='utf-8') print(bs) b = '你好'.encode('gbk') b1 = b.decode('gbk') print(b1.encode('utf-8'))
-
ord()
:输入字符寻找该字符编码的位置。chr()
:输入位置数字寻找其对应的字符。print(ord('a')) # 97 print(ord('中')) # 20013 print(chr(97)) # a print(chr(20013)) # 中
-
repr()
:全称 representation,返回一个对象的 string 形式(原封不动的返回)。# %r 原封不动的写出来 name = 'taibai' print('我叫%r'%name) # 我叫'taibai' print(repr('{"name":"alex"}')) # '{"name":"alex"}' print('{"name":"alex"}') # {"name":"alex"}
-
all()
:可迭代对象中,全都是True
会返回True
。any()
:可迭代对象中,只要有一个True
就会返回True
。print(all([1,2,True,0])) # False print(any([1,'',0])) # True