Day 10
迭代器和生成器
迭代器
-
说明:
迭代器时容器型数据类型(iter)
有如下特点:
1.不能同时直接查看所有元素(打印看不到其中元素)
2.不能直接统计个数
3.元素只能单个获取(每次获取最上层元素)
4.每次获取元素,元素都会从迭代器消失
-
创建迭代器
1.通过iter函数将其他序列转换为迭代器
2.通过生成器创建
iter1 = iter([1, 2, 3, 4]) iter2 = iter('abcde') print(iter1, type(iter1)) # <list_iterator object at 0x00000274DFBCE748> <class 'list_iterator'> print(iter2, type(iter2)) # <str_iterator object at 0x00000274DFBCEA20> <class 'str_iterator'> # print(len(iter1)) # 报错 - object of type 'list_iterator' has no len()
-
获取迭代器元素
语法:
1.获取单个元素
next(iteration)- 获取迭代器最上层的一个数据
2.遍历
for variable in iteration:
说明:
不管通过什么方式获取到迭代器中的元素,对应的元素都会从迭代器消失
print(next(iter1)) # 1 print(next(iter1)) # 2 next(iter1) print(next(iter1)) # 4 # next(iter1) # 报错 - StopIteration(迭代器为空) for i in iter2: print(i)
生成器
-
说明:
迭代器的特点和元素获取方式都适用
调用一个带有yield关键字的函数就可以创建一个生成器对象(如果被调用的函数里面有yield,不会执行函数体,也不会获取函数返回值)
# 尝试yield在不同位置会有什么变化 def func1(): yield print('abcde') # yield print([1, 2, 3, 4]) # yield return 0 # yield gen1 = func1() print(gen1)
-
确定生成器产生的数据
产生数据的个数:执行生成器对应的函数执行时会遇到的yield数量
产生的数据的值:每次遇到的yield后面的数据,没有数据就是None
def func3(x): yield 10 if x & 1: yield 20 return 30 yield 30 gen3 = func3(5) print(list(gen3)) # [10, 20] gen4 = func3(4) print(list(gen4)) # [10]
-
生成器原理
调用函数创建生成器对象的时候不会执行函数体,获取生成器中的元素的时候才会执行
第一次获取元素会从函数体开始位置开始执行,执行到第一次yield时暂停,并且将yield后面的数据作为这次获取到的元素
之后每次获取元素都会从上次暂停的位置向后执行,执行到yield时又会暂停
当某一次执行时到函数结束都没有遇到yield,用next获取元素时会报错 - StopIteration
def func4(): print('=1=') yield 100 print('=2=') yield 200 print('=3=') yield 300 print(next(func4())) # =1= 100 print(next(func4())) # =1= 100 gen5 = func4() gen6 = func4() print(next(gen5)) # =1= 100 x = next(gen5) # =2= print(x) # 200 print(next(gen5)) # =2= =3= 300 # next(gen5) # 报错 - StopIteration print(next(gen6)) # =1= 100(不会报错) # 编写一个产生一个学号的生成器,生成001~999的学生学号 # Python001~Python999 or Java001~Java999 def produce_num(project: str): for i in range(1, 1000): # 方法一: if i < 10: yield f'{project}00{i}' elif i < 100: yield f'{project}0{i}' else: yield project + str(i) # 方法二: yield f'{project}{i:0>3}' # 方法三: yield project + str(i).zfill(3) python_num = produce_num('Python') # print(list(python_num)) java_num = produce_num('Java') # print(next(java_num)) # 编写一个偶数生成器,产生正偶数 def produce_even(): num = 0 while True: yield num num += 2 num = produce_even() print(next(num)) print(next(num)) print(next(num)) print(next(num)) print(next(num)) for _ in range(50): print(next(num))
-
生成式 - 生成器的推导式
说明:
将列表推导式的 [] 变换为()即为生成器的推导式
gen_crate = ('str1' if z == 0 else f'str{z}' for z in range(0, 100, 3)) print(gen_crate) print(next(gen_crate)) print(next(gen_crate)) print(next(gen_crate)) print(next(gen_crate))
模块
-
说明:
在Python中一个py文件就是一个模块(可以在一个模块中使用另外一个模块(同一工程项目下)的内容,在使用前要导入模块)
只有全局变量、全局函数、全局类才能导入,统称为(广义)全局变量
-
导入模块
1.import 模块名(module’s name)-
使用模块中所有的全局变量;以module_name.variable的方式使用
2.from module_name import variable1, variable2,…… -
导入指定模块中指定的全局变量;可以直接使用变量
3.import module_name as new_name -
导入模块并用new_name命名;以new_name.variable的方式使用
4.from module_name import variable1 as new_variable1, variable2,…… -
导入模块中的变量并重命名某些变量;直接使用新变量或变量
5.from module_name import * -
导入模块中所有全局变量
-
注意:
import函数自带查重功能(导入多次也只会执行一次)
-
-
导入原理
不管是通过import还是from import,在导入模块时,系统会自动将被导入的模块中的所有代码运行一次
-
书写规范
在定义模块时,可以通过if __name__ == "__main__":这个if语句来阻止模块中指定代码在被其他模块导入时执行(在这个if语句中的代码不会被其他模块执行,不在if语句中的代码会被其他模块执行)
每个模块都会自带一个__name__变量,在没有运行模块时,__name__的值为当前__name__所在文件的文件名;在模块直接运行时__name__的值会变为"__main__",间接运行或不执行时__name__的值不会发生改变
def function1() pass def function2() pass …… def functionN() pass …… def main() function1() function2() functionN() …… if __name__ == "__main__": main()