了解Python中的list和dict的一些高级用法

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/fangfu123/article/details/83865868

list和dict是python中常用的列表和字典。
这里讨论一下他们的原理及一些高级用法,供大家查询参考。

list的切片

list的切片格式为:

list[start:end:step]

其中step如果没有,则默认为1
下面举例说明:
先定义一个list:

list = [1,2,3,4,5,6,7,8,9]

那么list[1:6:2],就表示从1位置开始到3位置结束,间隔2,结果如下:

list[1:6:2]
[2, 4, 6]

注意:list的切片操作会返回一个新的列表,切片并不会改变原list本身。

dict的浅拷贝及深拷贝

什么是dict(字典)的浅拷贝和深拷贝?
如果我们在已有指针的情况下,增加一个指针指向已经存在的内存,称为浅拷贝。
如果我们增加一个指针的同时也新增了内存,并且新指针指向到新内存,称为深拷贝。

注意区分dict的浅拷贝及深拷贝的区别。
下面举个例子说明一下:

import copy   

dict = {"a":{"a1":"a123"}, "b":{"b1":"b123"}}
a_dict = dict.copy()                # 浅拷贝
a_dict["a"]["a1"]="newa123"

b_dict = copy.deepcopy(dict)        #深拷贝
b_dict["b"]["b1"]="newb123"

print(dict)
print(a_dict)
print(b_dict)

浅拷贝会替换掉原来的的dict,而深拷贝会新建一个dict,不会替换掉原来的dict。

list转化为dict

在python3的环境下,list转化成dict。
下面每一步都复制了执行语句后的结果。便于参考。
先定义一个list:

>>> list = ["a1", "b1"]

通过dict.fromkeys方法创建一个新字典:

>>> dict_list = dict.fromkeys(list,{"aa1":"1234556"})
>>> dict_list
{'a1': {'aa1': '1234556'}, 'b1': {'aa1': '1234556'}}

通过get方法获取value的值,注意get的用法:

>>> value = dict_list.get("a1")
>>> value
{'aa1': '1234556'}

用update方法来修改dict:

>>> dict_list.update(a1="new123",b1="bbb123")
>>> dict_list
{'a1': 'new123', 'b1': 'bbb123'}

>>> dict_list.update((("a1","aaa123"),("b1","bbb123")))
>>> dict_list
{'a1': 'aaa123', 'b1': 'bbb123'} 

完整代码如下:

list = ["a1","b1"]
dict_list = dict.fromkeys(list,{"aa1":"1234556"})
value = dict_list.get("a1")
dict_list.update(a1="new123",b1="bbb123")
dict_list.update((("a1","aaa123"),("b1","bbb123")))

list和dict的实现原理

当我们定义一个list或者dict的时候,数据会存入内存中。
在list中随着list数据的增大,查找时间会增大,
而在dict中查找元素的时候,不会随着dict的增大而增大,
所以说dict查找的性能远大于list。

那么,为什么dict中查找元素的时候,时间会比查找list少呢?
dict背后实现原理是哈希表(hash),其特点是:
1、dict的key或者set的值,都必须是可以hash的,
就是说对不可变对象都是可hash的,比如str, fronzenset(不可变集合), tuple,
如果是自己实现的类,我们可以在类中加__hash__,这样我们的对象就是可hash对象
2、dict的内存花销大,但是查询速度快,自定义对象或python内部的对象都是用dict包装的。
3、dict的存储顺序和元素添加顺序有关。
4、添加数据有可能改变已有数据的顺序。
当表元(列表中的元素)小于三分之一,就会重新申请空间,在重新分配内存中,有可能重新改变顺序。

字典与列表dict和list
字典通过偏移量直接寻址。
查找原理大致步骤如下,原谅我不会画图:
1、计算键的散列值(哈希值)–>
2、使用散列值的一部分来定位散列表中的一个表元 -->
3、表元为空 --> 抛出keyerror
4、表元不为空 -->
5、判断键是否相等 -->
如果是 --> 返回表元里的值
如果否,表示散列冲突 -->
6、使用散列值的另一部分来定位散列表中的另一行 -->
7、表元为空 -->
8、返回前面第3步骤继续循环

set集合和frozenset集合

1、set集合是可变集合,可以添加,可以删除。
set集合没有hash值,它是无序的。不支持序列,不记录元素的位置。
2、frozenset集合是不可变集合,不能添加,一旦创建就不能删除。
frozenset可以作为字典的key,也可以作为其他集合的元素。

他们特点都是无序,不能重复的,如:
set集合是无序且不能重复的:

>>> s=set('abcdcee')
>>> s
{'d', 'e', 'b', 'a', 'c'}

set集合可以添加:

>>> s.add('g')
>>> s
{'d', 'e', 'b', 'a', 'c', 'g'}

frozenset集合也是是无序且不能重复的:

>>> ss=frozenset('123332')
>>> ss
frozenset({'3', '1', '2'})

注意frozenset集合是没有add方法的,也就是不能添加。

通过update来给set集合添加集合:

>>> ss=set('zyxzce')
>>> ss
{'e', 'z', 'y', 'x', 'c'}
>>> s.update(ss)
>>> s
{'d', 'e', 'z', 'y', 'b', 'x', 'a', 'c', 'g'}

difference可以查看集合之间的区别:

>>> s.difference(ss)
{'g', 'b', 'a', 'd'}

list和dict的类继承

list和dict本身也是类。
在我们定义类的时候,通常不建议继承list和dict。
因为在某些情况之下,用c语言写的dict,不会调用我们自定义的重新覆盖的方法。
如果实在要继承,可以用UserDict,如:

from collections import UserDict

class MyDict(UserDict):
    def __setitem__(self, key, value):
        super().__setitem__(key, value*2)
        
mydict = MyDict(a=1)

不建议的用法,这里只是顺带一提。

猜你喜欢

转载自blog.csdn.net/fangfu123/article/details/83865868