生成器:能够根据程序员指定的规则循环生成数据,条件不成立时生成数据结束,数据不是一次性全部生成处理,而是用一个再生成一个,是根据算法生成数据的一种机制,每次调用生成器只生成一个值,可以节省大量内存
创建生成器方式
类似列表推导式,生成器推导式使用小括号
- generator = (i**2 for i in range(6)) # 创建生成器
- print(generator)
- print('生成器中下一个值为:', next(generator), '再下一个值为:', next(generator))
- for v in generator: # 用一个生成一个,从next()之后继续生成
- print('遍历生成器,剩余值依次为:', v)
-
- 输出:
object at 0x000001BB6E8D2FF0> - 生成器中下一个值为: 0 再下一个值为: 1
- 遍历生成器,剩余值依次为: 4
- 遍历生成器,剩余值依次为: 9
- 遍历生成器,剩余值依次为: 16
- 遍历生成器,剩余值依次为: 25
只要在def定义的函数中看到yield关键字,则该函数即为一个生成器
- def generator(): # 函数中有yield关键字,则该函数即为生成器
- for i in range(6):
- print('开始生成数据')
- yield i + 2 # 执行到此处时,程序暂停执行,并将结果返回,当再次启动生成器时继续从此处往下执行
- print('完成一次数据生成')
- result = generator()
- print('result类型为:', type(result))
- print('生成器中下一个值为:', next(result))
- print('--------------------------------')
- print('生成器中再下一个值为:', next(result))
-
- # 遍历生成器方式1,for循环
- # for i in result: # for循环自动处理停止迭代异常
- # print('遍历生成器,剩余值依次为:', i)
-
- # 遍历生成器方式2,while循环
- # while True:
- # try:
- # print('遍历生成器,剩余值依次为:', next(result))
- # except StopIteration as e: # 处理迭代异常,生成最后一个数据时,会产生StopIteration异常
- # break
-
- 输出:
- result类型为: <class 'generator'>
- 开始生成数据
- 生成器中下一个值为: 2
- --------------------------------
- 完成一次数据生成
- 开始生成数据
- 生成器中再下一个值为: 3
使用生成器实现斐波那契数列,每次取值都通过算法来生成下一个数据,生成器每次调用只生成一个数据,可以节省大量的内存
斐波拉契数列(Fibonacci):数列中第一个数为0,第二个数为1,其后的每一个数都由前两个数相加得到
- def fibonacci(n): # n为生成个数
- a = 0 # 初始化前两个值
- b = 1
- i = 0 # 记录生成个数的索引
- while i < n:
- result = a
- a, b = b, a + b # 交换变量间的值
- i += 1
- yield result # 代码执行到yield会暂停,然后把结果返回出去,下次启动生成器会在暂停的位置继续往下执行
-
- generator = fibonacci(20) # 创建生成器
- list = []
- for v in generator:
- list.append(v)
- print('生成器生成的斐波那契数列值依次为:', list)
-
- 输出:
- 生成器生成的斐波那契数列值依次为: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
浅拷贝至多拷贝对象的一层,深拷贝可能拷贝多层,不论是浅拷贝或是深拷贝,只要拷贝成功就会开辟新的内存空间存储拷贝的对象
使用copy()函数进行浅拷贝,只对可变类型第一层对象进行拷贝,对拷贝对象开辟新的内存空间进行存储,不拷贝对象内部子对象
- import copy
- print('----------------------------------------不可变类型-------------------------------')
- # 拷贝后内存地址未变,说明未对对象进行拷贝,即浅拷贝不会对不可变类型的拷贝开辟新的内存空间
- # 对不可变类型的浅拷贝实际是对引用(内存地址)的拷贝,两个变量指向同一个内存地址
- print('-------------------数字------------------------')
- a = 13
- b = copy.copy(a)
- print('a值为:', a, 'a的内存地址为:', id(a), '\nb值为:', b, 'b的内存地址为:', id(b))
- print('-------------------字符串-----------------------')
- aa = 'abc'
- bb = copy.copy(aa)
- print('aa值为:', aa, 'aa的内存地址为:', id(aa), '\nbb值为:', bb, 'bb的内存地址为:', id(bb))
- print('--------------------元组------------------------')
- a2 = (1, 3, ['a', 2])
- b2 = copy.copy(a2)
- print('a2值为:', a2, 'a2的内存地址为:', id(a2), '\nb2值为:', b2, 'b2的内存地址为:', id(b2))
- print('a2[2]值为:', a2[2], 'a2[2]的内存地址为:', id(a2[2]), '\nb2[2]值为:', b2[2], 'b2[2]的内存地址为:', id(b2[2]))
-
- print('\n---------------------------------可变类型-------------------------------------')
- # 只对可变类型第一层对象进行拷贝,开辟新的内存空间
- # 不会拷贝最外层对象内的子对象
- print('--------------------列表------------------------')
- a3 = [1, 3, 5]
- b3 = copy.copy(a3)
- print('a3值为:', a3, 'a3的内存地址为:', id(3), '\nb3值为:', b3, 'b3的内存地址为:', id(b3))
- print('--------------------字典------------------------')
- a4 = {'id': 2, 'name': 'xx', 'age': '18'}
- b4 = copy.copy(a4)
- print('a4值为:', a4, 'a4的内存地址为:', id(a4), '\nb4值为:', b4, 'b4的内存地址为:', id(b4))
- print('--------------------集合------------------------')
- a5 ={1, 2, 3, 'aaa'}
- b5 = copy.copy(a5)
- print('a5值为:', a5, 'a5的内存地址为:', id(a5), '\nb5值为:', b5, 'b5的内存地址为:', id(b5))
- print('--------------------列表-----子对象--------------')
- a6 = [1, 3, 5, [2, 4]]
- b6 = copy.copy(a6)
- print('a6值为:', a6, 'a6的内存地址为:', id(a6), '\nb6值为:', b6, 'b6的内存地址为:', id(b6)) # 地址不同,只对第一层对象进行了拷贝,开辟了新空间
- print('a6[3]值为:', a6[3], 'a6[3]的内存地址为:', id(a6[3]), '\nb6[3]值为:', b6[3], 'b3[3]的内存地址为:', id(b6[3])) # 子对象内存地址不变,说明不会拷贝子对象
- a6.append(6)
- print('a6追加数据6后为:', a6, 'b6为:', b6) # 只有a6追加了,b6未追加,说明不是同一个地址
- a6[3][0] = 1
- print('a6子对象修改后为:', a6, ',b6为:', b6) # a6和b6的子对象均进行了修改,说明子对象是同一个地址
-
- 输出:
- ----------------------------------------不可变类型-------------------------------
- -------------------数字------------------------
- a值为: 13 a的内存地址为: 1938320720496
- b值为: 13 b的内存地址为: 1938320720496
- -------------------字符串-----------------------
- aa值为: abc aa的内存地址为: 1938321990192
- bb值为: abc bb的内存地址为: 1938321990192
- --------------------元组------------------------
- a2值为: (1, 3, ['a', 2]) a2的内存地址为: 1938325111232
- b2值为: (1, 3, ['a', 2]) b2的内存地址为: 1938325111232
- a2[2]值为: ['a', 2] a2[2]的内存地址为: 2211555234752 # 子对象内存地址相同,未开辟新空间
- b2[2]值为: ['a', 2] b2[2]的内存地址为: 2211555234752
-
- n---------------------------------可变类型-------------------------------------
- --------------------列表------------------------
- a3值为: [1, 3, 5] a3的内存地址为: 1938320720176
- b3值为: [1, 3, 5] b3的内存地址为: 1938604134016
- --------------------字典------------------------
- a4值为: {'id': 2, 'name': 'xx', 'age': '18'} a4的内存地址为: 1938322030912
- b4值为: {'id': 2, 'name': 'xx', 'age': '18'} b4的内存地址为: 1938322031168
- --------------------集合------------------------
- a5值为: {'aaa', 1, 2, 3} a5的内存地址为: 1938604957408
- b5值为: {'aaa', 1, 2, 3} b5的内存地址为: 1938604957856
- --------------------列表-----子对象--------------
- a6值为: [1, 3, 5, [2, 4]] a6的内存地址为: 1938604134528
- b6值为: [1, 3, 5, [2, 4]] b6的内存地址为: 1938604134208
- a6[3]值为: [2, 4] a6[3]的内存地址为: 1938604134976 # 子对象内存地址相同,未开辟新空间
- b6[3]值为: [2, 4] b3[3]的内存地址为: 1938604134976
- a6追加数据6后为: [1, 3, 5, [2, 4], 6] b6为: [1, 3, 5, [2, 4]]
- a6子对象修改后为: [1, 3, 5, [1, 4], 6] ,b6为: [1, 3, 5, [1, 4]]
使用deepcopy()进行深拷贝,只要对象有可变类型就会对该对象到最后一个可变类型的每一层对象进行拷贝,对每一层拷贝的对象都会开辟新的内存空间进行存储
不可变类型
可变类型
- import copy
- print('----------------------------------------不可变类型-------------------------------')
- # 不可变类型进行深拷贝,若子对象无可变类型,则不拷贝,只对引用(内存地址)拷贝
- # 若子对象有可变类型,则对该对象到最后一个可变类型的每一层对象进行拷贝, 对每一层拷贝的对象都会开辟新的内存空间进行存储
- print('-------------------数字------------------------')
- a = 13
- b = copy.deepcopy(a)
- print('a值为:', a, 'a的内存地址为:', id(a), '\nb值为:', b, 'b的内存地址为:', id(b))
- print('-------------------字符串-----------------------')
- aa = 'abc'
- bb = copy.deepcopy(aa)
- print('aa值为:', aa, 'aa的内存地址为:', id(aa), '\nbb值为:', bb, 'bb的内存地址为:', id(bb))
- print('--------------------元组------------------------')
- a2 = (1, 3, ['a', 2])
- b2 = copy.deepcopy(a2)
- print('a2值为:', a2, 'a2的内存地址为:', id(a2), '\nb2值为:', b2, 'b2的内存地址为:', id(b2))
- print('a2[2]值为:', a2[2], 'a2[2]的内存地址为:', id(a2[2]), '\nb2[2]值为:', b2[2], 'b2[2]的内存地址为:', id(b2[2]))
- print('\nn---------------------------------可变类型-------------------------------------')
- # 会对该对象到最后一个可变类型的每一层对象进行拷贝,对每一层拷贝的对象都会开辟新的内存空间进行存储
- print('--------------------列表------------------------')
- a3 = [1, 3, 5]
- b3 = copy.deepcopy(a3)
- print('a3值为:', a3, 'a3的内存地址为:', id(3), '\nb3值为:', b3, 'b3的内存地址为:', id(b3))
- print('--------------------字典------------------------')
- a4 = {'id': 2, 'name': 'xx', 'age': '18'}
- b4 = copy.deepcopy(a4)
- print('a4值为:', a4, 'a4的内存地址为:', id(a4), '\nb4值为:', b4, 'b4的内存地址为:', id(b4))
- print('--------------------集合------------------------')
- a5 ={1, 2, 3, 'aaa'}
- b5 = copy.deepcopy(a5)
- print('a5值为:', a5, 'a5的内存地址为:', id(a5), '\nb5值为:', b5, 'b5的内存地址为:', id(b5))
- print('--------------------列表-----子对象--------------')
- a6 = [1, 3, 5, [2, 4]]
- b6 = copy.deepcopy(a6)
- print('a6值为:', a6, 'a6的内存地址为:', id(a6), '\nb6值为:', b6, 'b6的内存地址为:', id(b6)) # 地址不同,只对第一层对象进行了拷贝,开辟了新空间
- print('a6[3]值为:', a6[3], 'a6[3]的内存地址为:', id(a6[3]), '\nb6[3]值为:', b6[3], 'b3[3]的内存地址为:', id(b6[3])) # 子对象内存地址不同,开辟了新空间
- a6.append(6)
- print('a6追加数据6后为:', a6, 'b6为:', b6) # 只有a6追加了,b6未追加,说明不是同一个地址
- a6[3][0] = 1
- print('a6子对象修改后为:', a6, ',b6为:', b6) # 只对a6的子对象进行了修改,说明子对象不是同一个地址
-
- 输出:
- ----------------------------------------不可变类型-------------------------------
- -------------------数字------------------------
- a值为: 13 a的内存地址为: 1465889784432
- b值为: 13 b的内存地址为: 1465889784432
- -------------------字符串-----------------------
- aa值为: abc aa的内存地址为: 1465891054128
- bb值为: abc bb的内存地址为: 1465891054128
- --------------------元组------------------------
- a2值为: (1, 3, ['a', 2]) a2的内存地址为: 1465894568256 # 含可变类型,内存地址不同,开辟了新空间
- b2值为: (1, 3, ['a', 2]) b2的内存地址为: 1466174359296
- a2[2]值为: ['a', 2] a2[2]的内存地址为: 1465890886592 # 子对象为可变类型,内存地址不同
- b2[2]值为: ['a', 2] b2[2]的内存地址为: 1466173393536
-
- n---------------------------------可变类型-------------------------------------
- --------------------列表------------------------
- a3值为: [1, 3, 5] a3的内存地址为: 1465889784112
- b3值为: [1, 3, 5] b3的内存地址为: 1466173181440
- --------------------字典------------------------
- a4值为: {'id': 2, 'name': 'xx', 'age': '18'} a4的内存地址为: 1465891094848
- b4值为: {'id': 2, 'name': 'xx', 'age': '18'} b4的内存地址为: 1465891094912
- --------------------集合------------------------
- a5值为: {'aaa', 1, 2, 3} a5的内存地址为: 1466174152416
- b5值为: {'aaa', 1, 2, 3} b5的内存地址为: 1466174152864
- --------------------列表-----子对象--------------
- a6值为: [1, 3, 5, [2, 4]] a6的内存地址为: 1466173392256
- b6值为: [1, 3, 5, [2, 4]] b6的内存地址为: 1466173392192
- a6[3]值为: [2, 4] a6[3]的内存地址为: 1466173393216 # 子对象为可变类型,内存地址不同
- b6[3]值为: [2, 4] b3[3]的内存地址为: 1466173392448
- a6追加数据6后为: [1, 3, 5, [2, 4], 6] b6为: [1, 3, 5, [2, 4]] # 内存不同,只追加给了a6
- a6子对象修改后为: [1, 3, 5, [1, 4], 6] ,b6为: [1, 3, 5, [2, 4]] # 因子对象内存不同,故只修改了a6的子对象
学习导航:http://xqnav.top/