• 数据类型(集合)以及深浅拷贝


    内容概要

      1、for循环原理

      2、set集合

      3、深浅拷贝

    主要内容:

      一、for循环原理

          先看以下示例:

    li = [11, 22, 33, 44] 
    for e in li:    
        li.remove(e) 
    print(li)                  # 结果: [22, 44]

        分析原因: for的运行过程,会有一个指针来记录当前循环的元素是哪一个,一开始这个指针指向第0个,然后获取到0个与那素,紧接着删除第0个。这个时候,原来的第一个元素会自动的往前补一个,变成第0个,然而指针会向后移动一次,指向现在的第一个,所以原来的第一个巧妙的躲过了!(本质上来说,for循环只是进行 索每次增加一的操作)   

    # 看看for的其他操作
    li = [11, 22, 33, 44] 
    for i in range(0, len(li)):    
        del li[i]
    print(li)                  # 结果: 报错!  原因:i = 0,1,2  当i=2是此时列表里只有两个数,索引最大才是1
    
    #试试 pop()
    for el in li:
        li.pop(el)
    print(li)             # 结果还是[11,22] 始终每次删除指针和位置缩进会导致错位的发生
    
    # 以下两种才是正解:
    for i in range(0, len(li):
        li.pop()                    # 让每一次删除的位置变化都记录下来
    
    print(li)
    
    # 或则用以下方法:
    del_li = []
    for e in li :
        dei_li.append(e)
    for e in del_li:
        li.remove(e)                # 来一个隔山打牛
    print(li)

        补充知识点:

          dic中的元素在迭代的过程中是不允许进行删除的

    dic = {'k1': 'alex', 'k2': 'wusir', 's1': '⾦⽼板'} # 删除key中带有'k'的元素 
    for k in dic:    
        if 'k' in k:        
            del dic[k]      # dictionary changed size during iteration, 在循环迭 代的时候不不允许进⾏行行删除操作 
    
    print(dic)
    
    #怎么办???  我们可以把要删除的元素记录下来,保存在一个列表中,然后再循环list,进行删除
    dic = {'k1': 'alex', 'k2': 'wusir', 's1': '⾦老板'} 
    dic_del_list = [] # 删除key中带有'k'的元素
    for k in dic:    
        if 'k' in k:        
            dic_del_list.append(k) 
    for el in dic_del_list:    
        del dic[el] 
    
    print(dic)


    类型转换:
      元组 ---> 列表 list(tuple)
      列表 ---> 元组 tuple(list)
      集合 ---> 列表 set(list)

    转换成False的数据:0,'',None,[],{},(),set()
    print(bool(set()))
    print(bool({}))


    dic = {"apple":"苹果", "banana":"香蕉"}  # 返回新字典. 和原来的没关系
    ret = dic.fromkeys("orange", "橘子")     # 直接用字典去访问fromkeys不会对原来的字典产生影响
    ret_1 = dict.fromkeys("abc",["哈哈","呵呵", "吼吼"]) # fromkeys直接使用类名进行访问,且默认生成一个新的字典
    print(ret)
    print(dic) # 对原来的字典dic没有影响 ,而 dict是个类名.fromkeys会生成一个另外的字典
    print(ret_1)

    结果:
    {'o': '橘子', 'r': '橘子', 'a': '橘子', 'n': '橘子', 'g': '橘子', 'e': '橘子'} {'a': ['哈哈', '呵呵', '吼吼'], 'b': ['哈哈', '呵呵', '吼吼'], 'c': ['哈哈', '呵呵', '吼吼']}

    a = ["哈哈","呵呵", "吼吼"]
    ret = dict.fromkeys("abc", a) # fromkeys直接使用类名进行访问
    a.append("嘻嘻")
    print(ret) # {'a': ['哈哈', '呵呵', '吼吼', '嘻嘻'], 'b': ['哈哈', '呵呵', '吼吼', '嘻嘻'], 'c': ['哈哈', '呵呵', '吼吼', '嘻嘻']}


    二 、set集合  

       set集合是python的⼀一个基本数据类型. ⼀一般不是很常⽤用. set中的元素是不重复的(去重).⽆无序的(没有固定的索引).⾥里里 ⾯面的元素必须是可hash的(int, str, tuple,bool), 我们可以这样来记. set就是dict类型的数据但 是不保存value, 只保存key. set也⽤用{}表示

      数据类型的总结:

        按存值个数区分

    标量/原子类型   数字,字符串
    容器类型     列表,元组,字典

        按可变不可变区分

    可变     列表,字典
    不可变    数字,字符串,元组

        按访问顺序区分

    直接访问   数字
    顺序访问(序列类型)   字符串,列表,元组
    key值访问(映射类型)

      字典

    集合的定义:   s = set()    # 这就创建了一个空集合

      1、集合的去重:   

    s = {'王立’ ,'王立''小珠'}
    
    print(s)   # 一定要区分集合和字典,字典是有键值对,而集合没有键值对!
    
    # 利用去重的特性我们可以讲一个含有重复数据的列表去重: set(list)
    
    # 注意: set集合中的元素必须是可hash的(也就是不可变元素),否则会报错!但是集合本身是可hash的 !
    
    set = {'1', 'wangli', True, [1, 2, 3]}   # 报错
    set_1 = {'2', 'xiaozhu', (1, 2, [2, 3, 4])  #同样会报错

      2、集合的增删改查:

        2.1、增加:

    s = {"刘嘉玲", '关之琳', "王祖贤"} 
    s.add("郑裕玲") 
    print(s)     
    s.add("郑裕玲")      # 重复的内容不不会被添加到set集合中 
    print(s)            # {'李若彤', '麻', '张曼⽟', '藤', '花', '王祖贤', '刘嘉玲', '关之琳'}
    
    s = {"刘嘉玲", '关之琳', "王祖贤"} 
    s.update("麻花藤")    # 迭代更更新
    print(s)             # {'李若彤', '麻', '张曼⽟', '藤', '花', '王祖贤', '刘嘉玲', '关之琳'}
    
    s.update(["张曼玉", "李若彤","李若彤"])  # 在列表里的也是迭代添加进去
     print(s)           # {'李若彤', '麻', '张曼⽟', '藤', '花', '王祖贤', '刘嘉玲', '关之琳'}

        2.2、删除:

    s = {"刘嘉玲", '关之琳', "王祖贤","张曼玉", "李若彤"} 
    item = s.pop()  # 随机弹出一个. 
    print(s) 
    print(item) 
    
    s.remove("关之琳") # 直接删除元素 
            # s.remove("马⻁疼") # 不存在这个元素. 删除会报错 
    print(s) 
    
    s.clear()    # 清空set集合.需要注意的是set集合如果是空的. 打印出来是set() 因为要和 dict区分的. 
    print(s)    # set()              

        2.3、修改:

    # set集合中的数据没有索引. 也没有办法去定位⼀一个元素. 所以没有办法进⾏行行直接修改. 
    # 我们可以采⽤用先删除后添加的⽅方式来完成修改操作 
    s = {"刘嘉玲", '关之琳', "王祖贤","张曼⽟玉", "李李若彤"} # 把刘嘉玲改成赵本⼭山 
    s.remove("刘嘉玲") 
    s.add("赵本⼭山") 
    print(s)

        2.4、查找:依旧遍历(没有索引)

    # set是⼀一个可迭代对象. 所以可以进⾏行行for循环
    for el in s:    
        print(el)

        2.5、常用操作:

    s1 = {"刘能", "赵四", "⽪⻓山"} 
    s2 = {"刘科长", "冯乡长", "⽪长山"}
    
    # 交集 
    # 两个集合中的共有元素 
    print(s1 & s2)  
    # {'⽪长⼭'} print(s1.intersection(s2))  # {'⽪⻓山'} 
    
    # 并集
    print(s1 | s2)            # {'刘科长', '冯乡长', '赵四', '⽪⻓山', '刘能'} print(s1.union(s2))     # {'刘科⻓', '冯乡长', '赵四', '⽪长山', '刘能'} 
    
    # 差集 
    print(s1 - s2)      # {'赵四', '刘能'} 得到第一个中单独存在的 print(s1.difference(s2))   # {'赵四', '刘能'} 
    
    # 反交集 
    print(s1 ^ s2)  # 两个集合中单独存在的数据 {'冯乡长', '刘能', '刘科长', '赵四'} 
    print(s1.symmetric_difference(s2)) # {'冯乡长', '刘能', '刘科长', '赵四'}
    
    s1 = {"刘能", "赵四"} 
    s2 = {"刘能", "赵四", "⽪长山"} 
    # 子集 
    print(s1 < s2)    # set1是set2的⼦集吗? True 
    print(s1.issubset(s2)) 
    
    # 超集 
    print(s1 > s2)     # set1是set2的超集吗? False 
    print(s1.issuperset(s2)
    
    
    set集合本⾝身是可以发生改变的. 是不可hash的. 我们可以使⽤用frozenset来保存数据. frozenset是不可变的. 也就是⼀个可哈希的数据类型 .
    s = frozenset(["赵本山", "刘能", "皮⻓山", "长跪"])
    dic = {s:'123'} # 可以正常使⽤用了了 
    print(dic)   #  {frozenset({'刘能', '赵本山', '皮⻓山', '长跪'}): '123'}  使其可以作键

    三、深浅拷贝:lst1 = ["何炅", "杜海涛","周渝民"]

    lst2 = lst1.copy()
    lst1.append("李嘉诚")
    print(lst1)
    print(lst2)
    print(id(lst1), id(lst2))
    
    lst1 = ["何炅", "杜海涛","周渝民", ["麻花藤", "马芸", "周笔畅"]]
    lst2 = lst1.copy()
    lst1[3].append("无敌是多磨寂寞")
    print(lst1)
    print(lst2)
    print(id(lst1[3]), id(lst2[3]))
    
    '''  运行结果:   
    ['何炅', '杜海涛', '周渝民', '李嘉诚']
    ['何炅', '杜海涛', '周渝民']
    2679402030856 2679401042568
    ['何炅', '杜海涛', '周渝民', ['麻花藤', '⻢马芸', '周笔畅', '无敌是多磨寂寞']]
    ['何炅', '杜海涛', '周渝民', ['麻花藤', '⻢马芸', '周笔畅', '无敌是多磨寂寞']]
    2679401060744 2679401060744
    '''
    
    浅拷贝:数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)
    但是第一层虽然拷贝了,但是可以直接修改,在第一层中如果存在嵌套地址,那么修改嵌套里面的数据,大家都会改:
    
    lst1 = ["何炅", "杜海涛","周渝民", ["麻花藤", "马芸",[2,3],"周笔畅"]]
    lst2 = lst1.copy()
    lst1[3].append("无敌是多磨寂寞")
    lst1[3][2].append('hahah')
    print(lst1)
    print(lst2)   #['何炅', '杜海涛', '周渝民', ['麻花藤', '马芸', [2, 3, 'hahah'], '周笔畅', '无敌是多磨寂寞']]
    ['何炅', '杜海涛', '周渝民', ['麻花藤', '马芸', [2, 3, 'hahah'], '周笔畅', '无敌是多磨寂寞']]
    
    深拷贝:数据完全不共享(复制其数据完完全全放独立的一个内存,完全拷贝,数据不共享)深拷贝就是完完全全复制了一份,且数据不会互相影响,因为内存不共享。
    import copy
    l1 = [1, 2, 3, [11, 22, 33]]
    # l2 = copy.copy(l1)  浅拷贝
    l2 = copy.deepcopy(l1)
    print(l1,'>>>',l2)
    l2[3][0] = 1111
    print(l1,">>>",l2)


    补充个面试题:
    a = [1, 2]
    a[1] = a

    print(a) # 结果: [1, [...]]

     

     

     代码块的缓存机制:

    Python在执行同一个代码块的初始化对象的命令时,会检查是否其值是否已经存在,如果存在,会将其重用。换句话说:执行同一个代码块时,遇到初始化对象的命令时,他会将初始化的这个变量与值存储在一个字典中,

    在遇到新的变量时,会先在字典中查询记录,如果有同样的记录那么它会重复使用这个字典中的之前的这个值。所以在你给出的例子中,文件执行时(同一个代码块)会把i1、i2两个变量指向同一个对象,满足缓存机制则

    他们在内存中只存在一个,即:id相同

    优点:能够提高一些字符串,整数处理人物在时间和空间上的性能;需要值相同的字符串,整数的时候,直接从‘池’里拿来用,避免频繁的创建和销毁,提升效率,节约内存。

    代码块的缓存机制的适用范围: int(float),str,bool。

    int(float):任何数字在同一代码块下都会复用。

    bool:True和False在字典中会以1,0方式存在,并且复用。

    str:几乎所有的字符串都会符合缓存机制,具体规定如下(了解即可!)

    1,非乘法得到的字符串都满足代码块的缓存机制:
    s1 = '太白@!#*ewq'
    s2 = '太白@!#*ewq'
    print(s1 is s2)  # True
    
    2、乘数得到的结果总长度小于20,当乘数是1时是都可以得
    s1 = 'old_' * 5
    s2 = 'old_' * 5
    print(s1 is s2)  # True
      

    小数据池:

    小数据池,也称为小整数缓存机制,或者称为驻留机制等等,博主认为,只要你在网上查到的这些名字其实说的都是一个意思,叫什么因人而异。

    那么到底什么是小数据池?他有什么作用呢?

    大前提:小数据池也是只针对 int(float),str,bool。

    小数据池是针对不同代码块之间的缓存机制!!!

    官方对于整数,字符串的小数据池是这么说的:

    Python自动将-5~256的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,而是使用已经创建好的缓存对象。

    python会将一定规则的字符串在字符串驻留池中,创建一份,当你将这些字符串赋值给变量时,并不会重新创建对象, 而是使用在字符串驻留池中创建好的对象。

    其实,无论是缓存还是字符串驻留池,都是python做的一个优化,就是将~5-256的整数,和一定规则的字符串,放在一个‘池’(容器,或者字典)中,无论程序中

    那些变量指向这些范围内的整数或者字符串,那么他直接在这个‘池’中引用,言外之意,就是内存中之创建一个。

    优点:能够提高一些字符串,整数处理人物在时间和空间上的性能;需要值相同的字符串,整数的时候,直接从‘池’里拿来用,避免频繁的创建和销毁,提升效率,节约内存。

    int:那么大家都知道对于整数来说,小数据池的范围是-5~256 ,如果多个变量都是指向同一个(在这个范围内的)数字,他们在内存中指向的都是一个内存地址。

    str:

    1、字符串的长度为0和1,默认都采用驻留机制。

    2、字符串的长度>1,且只含有大小写字母,数字,下划线时,才会默认。

     1 1.⽂件a.txt内容:每⼀⾏内容分别为商品名字,价钱,个数。
     2 通过代码,将其构建成这种数据类型:[{'name':'apple','price':10,'amount':3},
     3 {'name':'tesla','price':1000000,'amount':1}......] 并计算出总价钱。
     4 
     5 li=[]
     6 with open('a.txt',encoding='utf8',mode='r') as f:
     7     for i in f:
     8         i = i.split()
     9         dic =dict((('name',i[0]),('price', i[1]),('amount' ,i[2]))) # 妙处
    10         li.append(dic)
    11 sum = 0
    12 print(li)
    13 for i in li:
    14     sum += int(i.get('price')) * int(i.get('amount'))
    15 print(sum)
    16 
    17 2.有如下⽂件:将⽂件中所有的alex都替换成⼤写的SB(⽂件的改的操作)。
    18 
    19 import os
    20 with open('b.txt',encoding='utf8',mode='r') as f ,
    21     open('b.bak',encoding='utf8',mode='w') as f2:
    22     for i in  f:
    23         i = i.replace('alex','sb')
    24         f2.write(i)
    25 
    26 os.remove('b.txt')
    27 os.rename('b.bak','b.txt')
    28 
    29 3、⽂件a2.txt内容(升级题)通过代码,
    30 name:apple price:10 amount:3 year:2012
    31 name:tesla price:100000 amount:1 year:2013
    32 将其构建成这种数据类型[{'name':'apple','price':10,'amount':3,year:2012},
    33 {'name':'tesla','price':1000000,'amount':1}......] 并计算出总价钱。
    34 
    35 li = []
    36 sum = 0
    37 with open('a2.txt',encoding='utf8',mode='r') as f:
    38     for i in f:
    39         dic = {}
    40         a = i.split()
    41         for v in a:
    42             t = v.split(':')
    43             for c in t:
    44                 if t[1].isdigit():
    45                     dic[t[0]] = int(t[1])
    46                 else: dic[t[0]] = t[1]
    47 
    48         sum += dic['price']*dic['amount']
    49         li.append(dic)
    50 print(li)
    51 print(sum)
    52 
    53 4、念数字给出一个字典. 在字典中标识出每个数字的发音. 包括相关符号. 然后由用户输入一个数字.让程序读出相对应的发音(不需要语音输出. 单纯的打印即可)
    54 
    55 dic = {'-':'','0':'','1':'','2':'','3':'','4':'','5':'','6':'','7':'','8':'','9':'','.':'',}
    56 li = ['','','']
    57 while 1:
    58     usr = input('
    请输入(q退出,万位内):').strip()
    59     i,c=3,2
    60     if usr.startswith('-'):
    61         print('',end='')
    62         for a in usr[1:]:
    63             print(dic[a],end='')
    64             if len(usr)-i>=0:
    65                 print(li[len(usr)-i],end='')
    66                 i+=1
    67     elif '.' in usr:
    68         index = usr.find('.')
    69         for a in usr[:index]:
    70             print(dic[a],end='')
    71             if len(usr[:index])-c>=0:
    72                 print(li[len(usr[:index])-c],end='')
    73                 c+=1
    74         for i in usr[index:]:
    75             print(dic[i],end='')
    76     elif usr.lower() == 'q':
    77         break
    78     else:
    79         for a in usr:
    80             print(dic[a],end='')
    81             if len(usr)-c>=0:
    82                 print(li[len(usr)-c],end='')
    83                 c+=1
    练习题
    1、在python中只要是用引号引起来的就是字符串
    2、注意 (77)表示77 , (77,)表示元组,同理[77]
    3、在py2中,raw_input()与py3中的input类似,都是接受字符串类型。但是在py2中input(),是你输入什么类型,它接受的就是什么类型。
    4、 ASCII :不支持中文
          UTF-8:英文 1   中文3
           GBK  :英文1   中文2
       Unicode :英文 2  中文4 
    
    5、列表
           1、增加:append(),  insert(),   extend() 迭代添加、
           2、删除:pop() 、remove() 、clear()、del 切片
           3、改 : li[] = ''    注意索引修改时,如果有步长,则要一一对应
           4、查: 索引取值,或则 for循环
        列表的其他操作:
           5、 li.sort(reverse =True)  # 排序升序,降序)
            ###陷阱###
                lis = [1,2,3]
                new_list =lis.reverse()
                print(new_lis)     # None  注意是在原来的lis上修改,且返回值是None
             6、li.cout() #计数
             7、li.index()  #获取元素下标
            
    6、字典
        1、增: dic['key']=''   #索引增    dic.setdefault('key','value') #有则不变、无则添加
        2、删: dic.pop('key')   #按键删除,有返回值,dic.popitem() #随机删除
    dic.clear()  # 清空列表    del dic[] 
        3、改: dic['key'] = ''  #重新修改    dic.update(dic2) #有责修改,无则添加     
        4、查: dic.get()      dic['key']       for循环    dic.setdefault('key')
    
    
       字典的其他函数:
        5、dic=dict(('key','value'))   # 工厂化字典
        6、 dic.fromkeys()   
         #####坑####
    d = dict.fromkeys([1,2,3],10)   # 当值是一个不可变类型时
    print(d)      # {1: 10, 2: 10, 3: 10}
    d[1] = 20
    print(d)       # {1: 20, 2: 10, 3: 10}
    
    d = dict.fromkeys([1,2,3],[])
    print(d)     # {1: [], 2: [], 3: []}
    d[1].append(44)
    print(d)    #{1: [44], 2: [44], 3: [44]}
    
    
    基本数据类型补充:
    li = [1,2,3]
    for i in li:
        li.append(i)    # 这是一个无限循环的列表
    print(li)      
    前面知识讲解
  • 相关阅读:
    Chp18: Hard
    内存泄漏 和 内存溢出
    Chp4: Trees and Graphs
    trie树--详解
    Tries
    Comparable & Comparator
    memory leak
    8个月从CS菜鸟到拿到Google Offer的经历+内推
    Word Ladder II
    Java垃圾回收机制
  • 原文地址:https://www.cnblogs.com/double-W/p/9425499.html
Copyright © 2020-2023  润新知