python 2.081 深浅copy 迭代器 引出生成器

1.存放数据的容器

字符 布尔 整形 列表 字典 集合 元组 都可以存放数据

特点1  可变数据类型 ,这种数据容器就是id不变,值可变,不可以hash  ,元素可以任意更改
     不可变数据类型 ,这种数据容器就是id不变,值不可变,可以hash  ,元素不可以更改,如果更改了那就变成另一个变量了。
    


特点2 有序 和 无序 就是数据类型的元素有没有索引   列表是有序的对象集合   字典是无序的对象集合(3.9以上版本支持) 
     也就是说索引是数字,从0开始,元素有多个值。
     列表 有序,可修改,可重复
     字典 无序,可修改,key不可重复
     元组 有序,不可修改,可重复
     集合 无序,可修改,不可重复

特点3 数据类型的强弱
    python 是强类型 解释型语言
    
	

 针对特点1 数据类型的可变特性,引申出另一个问题就是复制数据的时候 copy 
        可变数据类型 ,复制是完全复制内存地址数据,新数据,旧数据修改,完全不相干。
        不可变数据类型,复制数据,是多了一个指定内存地址的变量名,数据共用一份,若修改,则全变。

1.3 深浅拷贝

  • 浅拷贝

    • 不可变类型,不拷贝。

      import copy
      
      v1 = "武沛齐"
      print(id(v1)) # 140652260947312
      
      v2 = copy.copy(v1) 
      print(id(v2)) # 140652260947312
      

      按理说拷贝v1之后,v2的内存地址应该不同,但由于python内部优化机制,内存地址是相同的,因为对不可变类型而言,如果以后修改值,会重新创建一份数据,不会影响原数据,所以,不拷贝也无妨。

    • 可变类型,只拷贝第一层。

      import copy
      
      v1 = ["武沛齐", "root", [44, 55]]
      print(id(v1))  # 140405837216896
      print(id(v1[2]))  # 140405837214592
      
      v2 = copy.copy(v1)
      print(id(v2))  # 140405837214784
      print(id(v2[2]))  # 140405837214592
      

      image-20210106151332792

  • 深拷贝

    • 不可变类型,不拷贝

      import copy
      
      v1 = "武沛齐"
      print(id(v1))  # 140188538697072
      
      v2 = copy.deepcopy(v1)
      print(id(v2))  # 140188538697072
      

      特殊的元组:

      • 元组元素中无可变类型,不拷贝

        import copy
        
        v1 = ("武沛齐", "root")
        print(id(v1))  # 140243298961984
        
        v2 = copy.deepcopy(v1)
        print(id(v2))  # 140243298961984
        
      • 元素元素中有可变类型,找到所有【可变类型】或【含有可变类型的元组】 均拷贝一份

        import copy
        
        v1 = ("武沛齐", "root", [11, [44, 55], (11, 22), (11, [], 22), 33])
        v2 = copy.deepcopy(v1)
        
        print(id(v1))  # 140391475456384
        print(id(v2))  # 140391475456640
        
        print(id(v1[2]))  # 140352552779008
        print(id(v2[2]))  # 140352552920448
        
        print(id(v1[2][1]))  # 140642999940480
        print(id(v2[2][1]))  # 140643000088832
        
        print(id(v1[2][2]))  # 140467039914560
        print(id(v2[2][2]))  # 140467039914560
        
        print(id(v1[2][3]))  # 140675479841152
        print(id(v2[2][3]))  # 140675480454784
        
    • 可变类型,找到所有层级的 【可变类型】或【含有可变类型的元组】 均拷贝一份

      import copy
      
      v1 = ["武沛齐", "root", [11, [44, 55], (11, 22), (11, [], 22), 33]]
      v2 = copy.deepcopy(v1)
      
      print(id(v1))  # 140391475456384
      print(id(v2))  # 140391475456640
      
      print(id(v1[2]))  # 140352552779008
      print(id(v2[2]))  # 140352552920448
      
      print(id(v1[2][1]))  # 140642999940480
      print(id(v2[2][1]))  # 140643000088832
      
      print(id(v1[2][2]))  # 140467039914560
      print(id(v2[2][2]))  # 140467039914560
      
      print(id(v1[2][3]))  # 140675479841152
      print(id(v2[2][3]))  # 140675480454784
      
      import copy
      
      v1 = ["武沛齐", "root", [44, 55]]
      v2 = copy.deepcopy(v1)
      
      print(id(v1))  # 140405837216896
      print(id(v2))  # 140405837214784
      
      
      print(id(v1[2]))  # 140563140392256
      print(id(v2[2]))  # 140563140535744
      

      image-20210106152704591

迭代器

针对特点2 数据类型的有序特性和无序特性,引申一个问题,要把一个变量的值依次取出,有序类型设置了索引值,根据索引取值,那么没有索引的类型如何依次取值。
 比如 字典 集合 文件,不依赖索引的取值方式是什么?

迭代:是一个重复的过程,但每次重复都是基于上一次的结果而来的。 
迭代器: 不依赖索引的取值工具,简单点就是能把字典 集合 文件的值依次取出来


dict_value = {
    'name':"aa",
    'age':"bb",
    'gender':"cc",
}

字典的迭代取值的需求如何实现 ,
详细过程解剖:

dict_iterator = dict_value.__iter__()  #字典内置了一个iter方法,调用,就是做成了一个迭代器,

res1 = dict_iterator.__next__() # 字典的迭代器调用next方法,就可以一个一个的取值。
res2 = dict_iterator.__next__()
res3 = dict_iterator.__next__()
print(res1)
print(res2)
print(res3)



简化代码  dit
dict_iterator = dict_value.__iter__()
while True:
    try:
        res = dict_iterator.__next__()
        print(res)
    except StopIteration:
        break


StopIteration  报错
name
age
gender


有__iter__方法的

没有索引的
1 字典
2 集合
3 文件对象或者句柄

有索引的
1、字符串
2、列表
3、元组


总结 python 不仅为有索引的数据类型配置了迭代取值的功能,也为没有索引的数据类型配置迭代取值的功能
迭代取值是python的通用的取值功能


这些数据类型就是通过__iter__的方法形成一个 可以迭代的数据类型,简称可迭代类型 或者可迭代对象




字典内置了一个iter方法,调用,就是做成了一个迭代器,

迭代器的对象有一个 __next__ 方法取值,, 为什么也有一个 __iter__()方法,

实验 迭代器对象调用iter方法 返回的是本身。
print(dict_iterator.__iter__() is dict_iterator)
 返回值 True
print([11,222,444].__iter__())
print({'name':"aa", 'age':"bb",'gender':"cc",}.__iter__())



dict_value = {
    'name':"aa",
    'age':"bb",
    'gender':"cc",
}
dict_iterator = dict_value.__iter__()

for 调用可迭代对象的iter方法,然后调用 迭代器对象的next的方法,依次读出数据
for  item in dict_value:
    print(item)

for 调用迭代器对象的的iter方法,然后调用 迭代器对象的next的方法,依次读出数据
for  item in dict_iterator:
    print(item)

最后 for 循环捕捉异常解释循环

while True:
    try:
        res = dict_iterator.__next__()
        print(res)
    except StopIteration:
        break



结论
1、在python的设计中,迭代取值是数据类型的通用方法,
不论是可迭代对象 或者是迭代器对象 都是可以通过 iter方法返回成 迭代器对象调用next方法迭代取值。
有iter方法的就是可迭代对象  所有的数据类型都是可迭代对象
有next方法的就是迭代器对象
只有 文件 既是迭代器对象,也是可迭代对象 只有文件才有可能有非常庞大的数据,所以直接做成 迭代器对象



2、迭代器 可以 惰性计算 ,节省内存。

目前使用的数据是已经创建的容器(比如字典中有100万个值),而要使用迭代器省内存就必须存进去100万个值,这样内存早就撑死了。
也就是目录使用的迭代器就是以现有数据转成的迭代器,达不到节省内存的效果、



引出自定义容器,也就是生成器。

posted @ 2021-12-26 21:08  mmszxc  阅读(62)  评论(0)    收藏  举报