美文网首页
python -- 元素和容器

python -- 元素和容器

作者: b485c88ab697 | 来源:发表于2017-09-04 23:07 被阅读15次

    元素和容器

    重点掌握列表、元组、字典、集合

    列表

    创建

    empty_list = [ ]
    empty_list =list()
    weekdays =['星期一','星期二','星期三','星期四','星期五','星期六','星期日’]
    name =['张三','李四','王五']
    

    Python 的list() 函数可以将其他数据类型转换成列表类型。

    list容器可以容纳不同类型的元素,相同元素可以出现多次,这点与set不同哦

    >>> list('abc')
    ['a', 'b', 'c’]
    >>> list('123')
    ['1', '2', '3’]
    >>> a_tuple = ('hello', 'world', 'python')
    >>> list(a_tuple)
    ['hello', 'world', 'python’]
    >>> birthday = '8/27/2017'
    >>> birthday.split('/')
    ['8', '27', '2017']
    >>>list = [1,'hello']
    

    获取元素

    通过偏移量可以从列表中提取对应位置的元素

    >>> marxes = ['Groucho', 'Chico', 'Harpo']
    >>> marxes[0]
    'Groucho'
    >>> marxes[1]
    'Chico'
    >>> marxes[2]
    'Harpo'
    

    包含列表的列表

    列表可以包含各种类型的元素,包括其他列表,如下所示:

    Quarter=[[1,2,3],[4,5,6],[7,8,9,],[10,11,12]]
    >>> print(Quarter)
    [[1, 2, 3], [4, 5, 6], [7, 8,9], [10, 11, 12]]
    >>> Quarter[1]
    [4, 5, 6]
    >>> Quarter[1][2]
    6
    

    列表修改

    Quarter=[[1,2,3],[4,5,6],[7,8,9,],[10,11,12]]
    >>> Quarter[2][2] = 0
    >>> print(Quarter)
    [[1, 2, 3], [4, 5, 6], [7, 8, 0], [10, 11, 12]]
    >>> Quarter[2][2]='0'
    >>> print(Quarter)
    [[1, 2, 3], [4, 5, 6], [7, 8, '0'], [10, 11, 12]]
    

    常用操作

    Quarter[0:2] 指定范围并使用切片提取元素
    Quarter.append(‘13’) 使用append()添加元素至尾部
    Quarter.extend(name) Quarter += others 使用extend()或+=合并列表 
    Quarter.insert(5, ‘14’) 使用insert()在指定位置插入元素
    del Quarter[-1] 使用del删除指定位置的元素
    Quarter.remove(‘13’) 使用remove()删除具有指定值的元素
    Quarter.pop(1) 使用pop()获取并删除指定位置的元素 pop()  如果不指定,默认弹出最后一个原始,即默认传入-1
    Quarter.index ([1,2,3])  使用index()查询具有特定值的元素位置
    ‘2' in Quarter 使用in判断值是否存在
    Quarter.count ([1,2,3])  使用count()记录特定值出现的次数
    '* '.join(marxes)  使用join()转换为字符串
    sorted(marxes)/ marxes.sort()  使用sort()重新排列元素
    len(marxes)  使用len()获取长度
    >>> a = [1, 2, 3]
    >>> b = a.copy()
    >>> c = list(a)
    >>> d = a[:] 使用=赋值,使用copy()复制
    

    需要注意extend是将后面的list中的元素,遍历出来放到前面list中,而append是直接将后面的list作为一个list放在源list后面

    list = ['1','2','3','4']
    list.append(['5','6'])
    print(list)
    list = ['1','2','3','4']
    list.extend(['5','6'])
    print(list)
    list = ['1','2','3','4']
    list = list.extend(['5','6'])
    print(list)
    ######################
    ['1', '2', '3', '4', ['5', '6']]
    ['1', '2', '3', '4', '5', '6']
    None
    

    注意:上面最后一次输出为什么是none,这是初学者很容易出现的问题,因为list的extend或者append函数,都是对源list进行修改,并没有返回值!

    在使用list时,需要注意,从一个list A直接用=传给另外一个list B时,是浅拷贝,修改B会导致A也被修改,如果不想被修改,请使用A.copy()/A[:]

    a = [1,'a','123']
    b = a
    c = a.copy() 
    #a[:]这样也可以 因为.copy是深拷贝,创建一个新的list,
    #[:]切片操作呢是创建一个新的list来接受切片的返回值,所以都是创建一个新的,所以对原来的不会造成影响
    b[2] = 0
    c[1] = 2
    print(a,b,c)
    >>>[1, 'a', 0] 
    [1, 'a', 0] 
    [1, 2, '123']
    

    注意copy对于list中嵌套的list可能有陷阱存在,因为嵌套进去的list其实是像是C的指针,指向真实的list

    a = [1,2,[3]]
    b = a.copy()
    b[0] = 100
    print(a,b)
    print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]))
    b[2][0] = [5]
    print(a,b)
    print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]))
    # b[2][0] = [7]
    # print(a,b)
    print('##########################')
    c = [1,2,[3]]
    d = c.copy()
    d[0] = 100
    print(c,d)
    print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))
    d[2] = [5]
    print(c,d)
    print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))
    
    #################################
    [1, 2, [239120930912]] [100, 2, [239120930912]]
    2145076863816 2145076863816 2145076962192 2145076962192
    [1, 2, [[5]]] [100, 2, [[5]]]
    2145076863816 2145076863816 2145076875976 2145076875976
    ##########################
    [1, 2, [3]] [100, 2, [3]]
    2145076877896 2145076877896 1902963216 1902963216
    [1, 2, [3]] [100, 2, [5]]
    2145076877896 2145076878088 1902963216 1902963280
    

    我们可以从上面的输出结果看到,

    a[2]的地址和b[2]完全一致,(2145076863816 2145076863816)

    a[2][0]与b[2][0]存储的list真实地址也是同一个

    a[2]此时存储的就是指向嵌套list的指针,而a[2][0]是嵌套list的真实地址。

    所以我们看到,当我们对于b的嵌套list的修改时,造成a,b两个的值的变化,是因为,我们修改的是嵌套list真实值,(嵌套list的真实地址变化了,从2145076962192 变到2145076875976)。

    而a[2]与b[2]这两个指针(实际是同一个指针)仍然指向的同一个list,只不过这个list本身的值被修改了,所以,a和b的值同时发生了变化。

    而c,d这两个例子,当我们d[2] = [5]时,是将d[2]里面存储的指针改成了指向list[5]所在的地址,所以对于d[2]的修改,并没有造成c[2]的变化。

    图有点丑,不过我想表达的意思已经表达出来了,当然也欢迎大触,来画一副更漂亮的图

    切片产生的新list,并不是引用原来的list,可以放心修改,并不会对源list造成改变。

    a = [1,2,3,4]
    b = a[0:2]
    b[1] = 100
    print(a,b)
    >>>[1, 2, 3, 4] [1, 100]
    

    但是对于list嵌套list。仍然会存在陷阱。

    a = [1,2,[3]]
    b = a[:]
    b[0] = 100
    print(a,b)
    print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]))
    b[2][0] = [5]
    print(a,b)
    print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]))
    # b[2][0] = [7]
    # print(a,b)
    print('##########################')
    c = [1,2,[3]]
    d = c[:]
    d[0] = 100
    print(c,d)
    print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))
    d[2] = [5]
    print(c,d)
    print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))
    #########################
    [1, 2, [3]] [100, 2, [3]]
    1686893585224 1686893585224 1902963216 1902963216
    [1, 2, [[5]]] [100, 2, [[5]]]
    1686893585224 1686893585224 1686893597384 1686893597384
    ##########################
    [1, 2, [3]] [100, 2, [3]]
    1686893599176 1686893599176 1902963216 1902963216
    [1, 2, [3]] [100, 2, [5]]
    1686893599176 1686893599368 1902963216 1902963280
    

    注意[]与list() []是代表生成一个list,而list()是将括号内的元祖,每个元素拿出来,充当list中的一个元素,而不是像[],将括号内的内容整个当做一个list的元素

    a = list('cat')
    b = ['cat']
    print(a,b)
    ['c', 'a', 't']
    ['cat']
    

    所以,新手容易遇到下面的报错问题

    a = [1,2,3,4]
    print(a)
    print(a.index(1))
    b = list('1234')
    print(b)
    print(b.index('1'))
    list = ['abc']
    print(list.index('a'))
    ###################
    [1, 2, 3, 4]
    0
    ['1', '2', '3', '4']
    0
    ##第三个是报错
    print(c.index('a'))
    ValueError: 'a' is not in list
    

    上面已经解释了,[]生成的元素以,号为分隔符,看第二行a的输出,而list()这个函数,会将()里面的tuple遍历,每个元素作为list的一个元素,看第五行b的输出,如果想要第三个不报错。可以这样写c = list('abc'),这样c里面其实是['a','b','c']

    对copy补充

    我们知道除了copy还是deepcopy 那么上面提到的copy陷阱还存在吗

    import copy
    
    a = [1,2,[3]]
    b = copy.deepcopy(a)
    b[0] = 100
    print(a,b)
    print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]))
    b[2][0] = [5]
    print(a,b)
    print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]),id(b[2][0][0]))
    # b[2][0] = [7]
    # print(a,b)
    print('##########################')
    c = [1,2,[3]]
    d = copy.deepcopy(c)
    d[0] = 100
    print(c,d)
    print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))
    d[2] = [5]
    print(c,d)
    print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))
    #############################
    [1, 2, [3]] [100, 2, [3]]
    1873715484872 1873716953800 1902963216 1902963216
    [1, 2, [3]] [100, 2, [[5]]]
    1873715484872 1873716953800 1902963216 1873716953736 1902963280
    ##########################
    [1, 2, [3]] [100, 2, [3]]
    1873716953672 1873716953480 1902963216 1902963216
    [1, 2, [3]] [100, 2, [5]]
    1873716953672 1873716953416 1902963216 1902963280
    

    首先,我们可以直观的看到,调用deepcopy后,a[2]与b[2]中的指针变化了!但是两个不同的指针却指向同一个list地址(第一行的输出 a[2][0]和b[2][0] 都是1902963216),

    在对b[2][0]重新赋值后,b[2][0]变成了list类型,存储了指向b[2][0][0]的指针,在图上可以看到,18开头数字更长的是type是list,而19开头,更短的是int类型。

    c,d的变化和调用copy一样

    元组

    与列表类似,元组也是由任意类型元素组成的序列。与列表不同的是,元组是不可变

    的,这意味着一旦元组被定义,将无法再进行增加、删除或修改元素等操作。因此,
    元组就像是一个常量列表。

    >>> empty_tuple = ()
    >>> empty_tuple
    ()
    

    创建

    创建包含一个或多个元素的元组时,每一个元素后面都需要跟着一个逗号,即使只包

    含一个元素也不能省略:

    >>> weekdays='星期一',
    >>> weekdays
    ('星期一’,)
    

    如果创建的元组所包含的元素数量超过1,最后一个元素后面的逗号可以省略,采用tuple来创建也可以省略,号:

    >>> weekdays='星期一','星期二','星期三'
    >>> weekdays
    ('星期一', '星期二', '星期三')
    >>>a = tuple('1')
    ('1',)
    

    Python 的交互式解释器输出元组时会自动添加一对圆括号。你并不需要这么做——

    定义元组真正靠的是每个元素的后缀逗号——但如果你习惯添加一对括号也无可厚非。
    可以用括号将所有元素包裹起来,这会使得程序更加清晰:

    >>> weekdays=('星期一','星期二','星期三')
    >>> weekdays
    ('星期一', '星期二', '星期三’)
    >>> Monday ,Tuesday,Wednesday = weekdays
    >>> Monday
    '星期一'
    

    请思考以下小问题:下面的1,2,3 是什么类型 ?

    a,b,c = 1,2,3
    print(a,b,c)
    

    请看下面例子

    a,b,c = 1,2,3
    print(a,b,c)
    
    d = 1,2,3
    print(type((1,2,3)))
    
    e,f,g = (1,2,3)
    print(e,f,g)
    ##############
    1 2 3
    <class 'tuple'>
    1 2 3
    

    我们可以看到,d的类型是tuple,那么1,2,3的类型就是tuple,后面的(1,2,3) 这个写法可能看起来更明确像tuple。我们回顾之前给出的定义

    定义元组真正靠的是每个元素的后缀逗号

    a,b,c = [5,6,[1,2,3]]
    print(a,b,c)
    

    有同学说我想直接让c取出来的值为2,而不是像现在取出来的是list

    #解1
    a,b,(e,c,f)= [5,6,[1,2,3]]
    print(c)
    #解2 直接在原数据上做修改 这种做法不太通用 
    a,b,c= [5,6,[1,2,3][1]]
    print(c)
    

    字典

    字典(dictionary)与列表类似,但其中元素的顺序无关紧要,因为它们不是通过像0 或1的偏移量访问的。取而代之,每个元素拥有与之对应的互不相同的键(key),需要通过键来访问元素。键通常是字符串,但它还可以是Python 中其他任意的不可变类型:布尔型、整型、浮点型、元组、字符串,以及其他一些在后面的内容中会见到的类型。字典是可变的,因此你可以增加、删除或修改其中的键值对。

    >>> empty_dict = {}
    >>> empty_dict,type(empty_dict)
    {} <class 'dict'>
    
    >>> e2cn={'apple':'苹果,是一种很甜的水果','cat':'猫,一种很可爱的动物'}
    >>> e2cn
    {'apple': '苹果,是一种很甜的水果', 'cat': '猫,一种很可爱的动物’}
    

    可以用dict() 将包含双值子序列的序列转换成字典

    >>> lol = [ ['a', 'b'], ['c', 'd'], ['e', 'f'] ]
    >>> dict(lol)
    {'c': 'd', 'a': 'b', 'e': 'f'}
    >>>d = dict(["ab", "cd", "ef"])
    {'a': 'b', 'c': 'd', 'e': 'f'} #可以把字符串转为字典,但是必须每个字符串长度为2
    
    >>> name = {
    ... '三' : '张',
    ... '四' : '李',
    ... '小明': '王',
    ... '小红': '张'
    ... }
    >>> name
    {'三': '张', '四': '李', '小明': '王', '小红': '张'}
    >>> name['二狗']='李'
    >>> name
    {'三': '张', '四': '李', '小明': '王', '小红': '张', '二狗': '李'}
    >>> name2 = {'小红':'王','三丰':'张'}
    >>> name.update(name2)
    >>> name
    {'三': '张', '四': '李', '小明': '王', '小红': '王', '二狗': '李', '三丰': '张'}
    #update会将name中没有的键值对复制进来,但是如果name2中存在key一样,value却不一致的情况,那么value会被更新成name2中的值,
    #其实可以看做key相同,则覆盖;如果没有,则追加。
    >>>name['二狗'] = '王'
    

    常用操作

    del name[‘三丰’] 使用del删除具有指定键的元素
    name.clear() 使用clear()删除所有元素
    ‘小红' in name 使用in判断是否存在
    name[‘小红’] 使用[key]获取元素
    name.keys() 使用keys()获取所有键
    name.values() 使用values()获取所有值
    name.items() 使用items()获取所有键值对
    

    遍历字典

    d = dict(["ab", "cd", "ef"])
    for item in d.items():
        print(item,type(item))
    for k,v in d.items():
        print(k,v)
    for a in d:
        print(a)
    #################################
    ('a', 'b') <class 'tuple'>
    ('c', 'd') <class 'tuple'>
    ('e', 'f') <class 'tuple'>
    a b
    c d
    e f
    a
    c
    e
    

    可以看出,.items()是把字典中的kv对,以tuple的形式拿出来。第二种遍历,则是直接把key,value取出来进行多元赋值。第三种注意,只能取出key。

    d = dict(["ab", "cd", "ef"])
    print(d.get('a','不存在'))
    print(d.get('d'))
    print(d.get('d','不存在'))
    ##################
    b
    None
    不存在
    

    在取值的时候,为了避免报错,我们可以采用get来取值,而不是直接d['xxx']。用get取值,不存在时,默认输出none,可以自定义不存在时的输出结果。

    下面是一个小坑,需要注意

    d2 = {"name":"zhangsan", "age":23, "salary":6500.0}
    d5 = d2
    print(id(d2), id(d5),id(d2['salary']),id(d5['salary']))
    d5["salary"] = 11000
    print(d2["salary"])
    print(id(d2), id(d5),id(d2['salary']),id(d5['salary']))
    #########################
    2081072900640 2081072900640 2081071833544 2081071833544
    11000
    2081072900640 2081072900640 2081071804112 2081071804112
    

    惯例,我们用图说话

    由此我们可以看出,d5["salary"] = 11000,改变的是指针指向的真实地址,而d2与d5的salary键指针是一样的.

    排序

    d6 = {"a1":["m1", 23], "c1":["n1", 20], "b1":["n1",22]}
    #按照key排序
    d7 = sorted(d6.items()) #对dict排序,一定使用dict.items()
    #按照value中的第2个元素排序
    d8 = sorted(d6.items(), key=lambda x:x[1][1])   #x表示tuple,那么x[1][1]表示value中的第2个元素
    print(d8)
    

    集合

    集合就像舍弃了值,仅剩下键的字典一样。键与键之间也不允许重复。如果你仅仅想知道

    某一个元素是否存在而不关心其他的,使用集合是个非常好的选择。如果需要为键附加其
    他信息的话,建议使用字典。

    >>> empty_set = set()
    >>> empty_set
    set()
    >>> even_numbers = {0, 2, 4, 6, 8}
    >>> even_numbers
    {0, 8, 2, 4, 6}
    >>> odd_numbers = {1, 3, 5, 7, 9}
    >>> odd_numbers
    {9, 3, 1, 5, 7}
    

    常用操作

    set( 'letters’ ) 使用set()将其他类型转换为集合
    set([1,2,3,4,5]) 用列表建立集合
    set((‘a’,‘b’,‘c’,‘d’)) 用元组建立集合
    set(name) 当字典作为参数传入set() 函数时,只有键会被使用
    s.add( x )  将元素 x 添加到集合s中,若重复则不进行任何操作
    update( x ) 将集合 x 并入原集合s中
    discard( x ) 将 x 从集合s中移除,若x不存在,不会引发错误
    remove( x )  将 x 从集合s中移除,若x不存在,会引发错误
    pop()  集合无序,所以随机删除并返回集合s中某个值
    x in s set同样支持in操作
    

    合并及运算符

    >>> a = {1, 2}
    >>> b = {2, 3}
    >>> a & b
    {2}
    >>> a.intersection(b)
    {2}
    >>> a | b
    {1, 2, 3}
    >>> a.union(b)
    {1, 2, 3}
    >>> a - b
    {1}
    >>> a.difference(b)
    {1}
    >>> a ^ b
    {1, 3}
    >>> a.symmetric_difference(b)
    {1, 3}
    >>> a <= b
    False
    >>> a.issubset(b)
    False
    >>> a <= a
    True
    >>> a.issubset(a)
    True
    

    相关文章

      网友评论

          本文标题:python -- 元素和容器

          本文链接:https://www.haomeiwen.com/subject/ruuyjxtx.html