第七天 18/5/7 基础数据类型的补充【fromkeys】 、 python的集合、深浅copy

一、基础数据类型的补充

  1)如果元组里面只有一个元素且没有逗号 “,” 则该数据的数据类型与里面的元素相同。

tu1 = ([1, 2, 3])                  #列表
tu2 = ([1, 2, 3],)
tu3 = ([1, 2, 3],[4, 5])
print(tu1,type(tu1))
print(tu2,type(tu2))
print(tu3,type(tu3))

[1, 2, 3] <class 'list'>           #列表
([1, 2, 3],) <class 'tuple'>
([1, 2, 3], [4, 5]) <class 'tuple'>

  2)循环一个列表(字典)时,最好不要改变列表(字典)的大小(增删),否则会影响你的最终结果或者报错。

例题:  li = [111, 222,333, 444, 555, 6, 7, 8, 9] 删除索引为奇数位

 1 li = [111, 222,333, 444, 555, 6, 7, 8, 9]
 2 for i in range(0,len(li)-1):
 3     print('删除之前的索引:',i)
 4     print('删除之前的列表:',li)
 5     if i % 2 == 1:
 6         del li[i]
 7     print('删除之后的索引:',i)
 8     print('删除之后的列表:',li)
 9 
10 删除之前的索引: 0
11 删除之前的列表: [111, 222, 333, 444, 555, 6, 7, 8, 9]
12 删除之后的索引: 0
13 删除之后的列表: [111, 222, 333, 444, 555, 6, 7, 8, 9]
14 删除之前的索引: 1
15 删除之前的列表: [111, 222, 333, 444, 555, 6, 7, 8, 9]
16 删除之后的索引: 1
17 删除之后的列表: [111, 333, 444, 555, 6, 7, 8, 9]
18 删除之前的索引: 2
19 删除之前的列表: [111, 333, 444, 555, 6, 7, 8, 9]
20 删除之后的索引: 2
21 删除之后的列表: [111, 333, 444, 555, 6, 7, 8, 9]
22 
23 #前面的都没问题
24 
25 删除之前的索引: 3
26 删除之前的列表: [111, 333, 444, 555, 6, 7, 8, 9]
27 删除之后的索引: 3
28 删除之后的列表: [111, 333, 444, 6, 7, 8, 9]
29 
30 # 3在原代码中:444  但在这里(删除之前的列表) 3指的是:555
31 #列表会变,但索引还是按之前的索引删就错了
32 
33 删除之前的索引: 4
34 删除之前的列表: [111, 333, 444, 6, 7, 8, 9]
35 删除之后的索引: 4
36 删除之后的列表: [111, 333, 444, 6, 7, 8, 9]
37 删除之前的索引: 5
38 删除之前的列表: [111, 333, 444, 6, 7, 8, 9]
39 删除之后的索引: 5
40 删除之后的列表: [111, 333, 444, 6, 7, 9]
41 删除之前的索引: 6
42 删除之前的列表: [111, 333, 444, 6, 7, 9]
43 删除之后的索引: 6
44 删除之后的列表: [111, 333, 444, 6, 7, 9]
45 删除之前的索引: 7
46 删除之前的列表: [111, 333, 444, 6, 7, 9]
错误示范

  正确答案:切片最简单  应该倒着删,否则列表会变但索引依旧是li的元索引

 = [111, 222,333, 444, 555, 6, 7, 8, 9]
for i in range(len(li)-1,-1,-1):  #len(li)计算 li 总长度, len(li)-1 :最后一位索引。 
    # -1 :第一位之前,过头不顾尾,取不到第一位,所以【0-1=-1】 -1:倒着隔一位取一个
    if i % 2 == 1:
        del li[i]
print(li)

[111, 333, 555, 7, 9]

    dic = {'k1':'v1','k2':'v2','k3':'v3','name':'alex'}删除含“k”的键

dic = {'k1':'v1','k2':'v2','k3':'v3,','name':'alex'}
li = []
for i in dic:          #  for 循环 dic 键
    if "k" in i:      #如果 dic 的键里含 “k”
        del dic[i]
print(dic)

RuntimeError: dictionary changed size during iteration
运行时错误:字典在迭代过程中改变了大小

  正确答案:在遍历的过程中 绝对 不能有任何改变

dic = {'k1':'v1','k2':'v2','k3':'v3,','name':'alex'}
li = []
for i in dic:         #  for 循环 dic 键
    if "k" in i:      #如果 dic 的键里含 “k”
        li.append(i)
for a in li:          #  for 循环 dic 的键
    del dic[a]
print(dic)

{'name': 'alex'}

   3)fromkeys:返回一个新的,带有(可迭代的键)和(值等于值的键)。

    常用于创建有规律的字典   

# 如何通过一行语句创建一个这样的字典{1: 'alex', 2: 'alex', 3: 'alex'}?

dic = dict.fromkeys([1,2,3],'alex')
print(dic)

{1: 'alex', 2: 'alex', 3: 'alex'}

###  fromkeys 虽然很好用,但是有个坑 【字典的值是容器类型,可变时】

dic = dict.fromkeys([1,2,3],[])
print(dic)

{1: [], 2: [], 3: []}


dic[1].append(666)     # 我给 1 的列表加 666
print(dic)

{1: [666], 2: [666], 3: [666]} #    1 2 3 这三个列表在内存中用的是一个

二、集合 (set)

  集合是无序的,不重复的数据集合,集合本身是可变的(增删查)【因为是无序的,所以没办法修改】,但是它却要求它里面的元素是不可变的(可哈希)【所以集合是做不了字典的键,但里面的元素可以做字典的键

  集合最重要的两点:

    1)去重(chong 重复)把一个列表变成集合,自动去重。

        set = set(list)

    2)关系测试,测试两组数据之间的交集、差集、并集等

  1)集合的创建

set1 = set()           #  小括号  创建空集合
print(set1,type(set1))
set2 = {'aass',5,9,True}   #  大括号,创建非空集合
print(set2)

set() <class 'set'>
{9, 'aass', 5, True} <class 'set'>

  2)增:.add() 直接加  

      .update() 迭代着增加 【字典里是两个字典之间的更新】

els = {'taibai','alex','wusir'}
els.add('女神')
print(els)

{'alex', '女神', 'wusir', 'taibai'}  #集合特性:无序。所以新加的内容的位置会随机
{'女神', 'alex', 'taibai', 'wusir'}
els = {'taibai','alex','wusir'}
els.update('女神')
print(els)

{'', 'taibai', 'wusir', 'alex', ''}

els = {'taibai','alex','wusir',}
els.update(['女神'])     #加中括号
print(els)

{'wusir', 'taibai', 'alex', '女神'}

  3)删 .pop() 随机删

      del 集合  删除集合

     .clear() 清空集合

     .remove(元素) 删除一个元素  【列表:按元素删除】

set1 = {'taibai','alex','wusir','yue'}
print(set1.pop())           # pop 有返回值    随机删
print(set1)

alex
{'taibai', 'wusir', 'yue'}
set1 = {'taibai','alex','wusir','yue'}
del set1
print(set1)

NameError: name 'set1' is not defined
set1 = {'taibai','alex','wusir','yue'}
print(set1.clear())     # 清空集合  没有返回值
print(set1)

None
set()
set1 = {'taibai','alex','wusir','yue'}
print(set1.remove('taibai'))   #按元素删  没有返回值
print(set1)

None
{'wusir', 'yue', 'alex'}

  4)查 因为集合是无序的,所以没办法用索引,只能 for 循环

set1 = {'taibai','alex','wusir','yue'}
for i in set1:
    print(i)
                               # 结果是无序的
alex
taibai
wusir
yue

  5)集合的其他操作:

    1)去重

set1 = {1, 1, 1, 1, 1, 1, 1, 1, 1}
print(set1)

{1}

    2)关系测试:

      1)交集  (& 或 intersection)

set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
print(set1 & set2)
print(set1.intersection(set2))

{4, 5}
{4, 5}

      2)并集  (| 或 union)

set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
print(set1 | set2)
print(set1.union(set2))

{1, 2, 3, 4, 5, 6, 7, 8}
{1, 2, 3, 4, 5, 6, 7, 8}

      3)差集  (- 或 difference)

set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
print(set1 - set2)       # 对于 set1 来说,它的差值是
print(set2.difference(set1))    #  对于 set2 来说,它的差值是

{1, 2, 3}
{8, 6, 7}

      4)反交集  (^ 或 symmetric_difference)

set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
print(set1 ^ set2)
print(set2.symmetric_difference(set1)

{1, 2, 3, 6, 7, 8}
{1, 2, 3, 6, 7, 8}

      5)子集与超集 issubset “<” “>”

set1 = {1, 2, 3}
set2 = {1, 2, 3, 4, 5}
print(set1 > set2)
print(set2.issubset(set1))   # 判断set2 是否是 set1 的子集

print(set1 < set2)
print(set1.issubset(set2))    # 判断set2 是否是 set1 的超集

False
False
True
True
set1 = {1, 2, 3}
set2 = {1, 2, 3}
print(set2.issubset(set1))   # 判断set2 是否是 set1 的子集
print(set1.issubset(set2))    # 判断set1 是否是 set 的子集

print(set1 > set2)
print(set1 < set2)

True
True
False
False
#  set1 与 set2  互为子集,互为超集

      6)frozenset  不可变集合,让集合变成不可变类型【集合本身是可变的】

set = {'d', 5, 9, 7}
set2 = frozenset(set)  # 冻结
set.update('bsd')      # 迭代增加 ‘b','s','d'
print(set2.pop())      # 随机删
print(set2)

frozenset({'d', 9, 5, 7})
AttributeError: 'frozenset' object has no attribute 'update'
AttributeError:“frozenset”对象没有属性“更新”
AttributeError: 'frozenset' object has no attribute 'pop'
#AttributeError:'frozenset'对象没有属性'pop'

三、深浅copy

  我们先看赋值运算

l1 = [1, 2, 3, ['barry','alex']]
l2 = l1
l1[0] = 111   # 将 1 改成 111 。l1 与 l2 都改变了
print(l1)
print(l2)

l1[3][0] = 'taibai'  #将 ‘barry’ 改成 ‘taibai’。l1 与 l2 都改变了
print(l1)
print(l2)

[111, 2, 3, ['barry', 'alex']]
[111, 2, 3, ['barry', 'alex']]
[
111, 2, 3, ['taibai', 'alex']] [111, 2, 3, ['taibai', 'alex']]

对于赋值运算来说,l1与l2指向的是同一个内存地址,所以他们是完全一样的

  1)浅 copy   拷贝

l1 = [1, 2, 3, ['barry','alex']]
l2 = l1.copy()
print(l1 , id(l1)) #[1, 2, 3, ['barry', 'alex']] 2079355846088
print(l2, id(l2))  # [1, 2, 3, ['barry', 'alex']] 2079357049160

l1[1] = 0
print(l1,id(l1)) #[1, 0, 3, ['barry', 'alex']] 2079355846088
print(l2,id(l2)) #[1, 2, 3, ['barry', 'alex']] 2079357049160
                                # 内存地址不同,所以这是两个列表, l1 做出了改变,而 l2 没有改变
l1[3][0] = 'taibai'
print(l1,id(l1[3])) #[1, 0, 3, ['taibai', 'alex']] 2079357059272
print(l2,id(l2[3])) #[1, 2, 3, ['taibai', 'alex']] 2079357059272
                                # 内存地址相同,所以 l1 与 l2 共用一个['barry','alex']

 

对于浅copy来说,第一层创建的是新的内存地址,而从第二层开始,指向的都是同一个内存地址,所以,对于第二层以及更深的层数来说,保持一致性。

    1.1)对于切片来说,这是浅copy

l1 = [1, 2, 3, ['barry','alex']]
l2 = l1[::1]
print(l2) #[1, 2, 3, ['barry', 'alex']]

l1[0] = 56
print(l1,id(l1)) #[56, 2, 3, ['barry', 'alex']] 2255049604552
print(l2,id(l2)) #[1, 2, 3, ['barry', 'alex']] 2255050807624

l1[-1][0] = 'taibai'
print(l1,id(l1[-1])) #[56, 2, 3, ['taibai', 'alex']] 2255050817736
print(l2,id(l2[-1])) #[1, 2, 3, ['taibai', 'alex']] 2255050817736

  2) 深层拷贝 deepcopy

import copy    # 一定不能缺
l1 = [1, 2, 3, ['barry','alex']]
l2 = copy.deepcopy(l1)    #完全复制

print(l1,id(l1))  #[1, 2, 3, ['barry', 'alex']] 2113649875272
print(l2,id(l2))  #[1, 2, 3, ['barry', 'alex']] 2113650028872

l1[1] = 222
print(l1,id(l1))  #[1, 222, 3, ['barry', 'alex']] 2113649875272
print(l2,id(l2))  #[1, 2, 3, ['barry', 'alex']] 2113650028872

l1[3][0] = 'taibai'
print(l1,id(l1))  #[1, 222, 3, ['taibai', 'alex']] 2113649875272
print(l2,id(l2))  #[1, 2, 3, ['barry', 'alex']] 211365002887

对于深copy来说,两个是完全独立,改变任意一个的任意元素(无论多少层),另一个绝对不变

猜你喜欢

转载自www.cnblogs.com/songzijian/p/9004414.html