Python中list和dict的高级用法详解:切片、浅拷贝与深拷贝原理

这里讨论一下他们的原理及一些高级用法,供大家查询参考。
list的切片
list的切片格式为:
list[start:end:step]
其中step如果没有,则默认为1
下面举例说明:
先定义一个list:
list = [1,2,3,4,5,6,7,8,9]
那么 list 从 1 位置开始,到 3 位置结束,间隔为 2,其结果如下:
list[1:6:2]
[2, 4, 6]
核心意思:强调在改写句子时要遵循特定的语言风格和要求,将长句拆分成简短的分句,以达到更好的表达效果。
dict的浅拷贝及深拷贝
什么是dict(字典)的浅拷贝和深拷贝?
如果已有指针,然后增加一个指针去指向已存在的内存,这种情况就被称为浅拷贝。
如果我们增加了一个指针,并且同时新增了内存,新指针指向了新内存,这种情况就被称为深拷贝。
注意区分dict的浅拷贝及深拷贝的区别。
下面举个例子说明一下:
import copy
dict 包含两个键值对,其中一个键为 "a",对应的值为 {"a1":"a123"};另一个键为 "b",对应的值为 {"b1":"b123"}。
a_dict 进行了浅拷贝操作,得到了一个新的字典,这个新字典与原字典内容相同,但不是同一个对象。
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 进行替换。
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的用法:
获取 dict_list 中的 "a1" 对应的值赋给 value 。
>>> value
其包含的键为 'aa1',对应的值为 '1234556'。
用update方法来修改dict:
dict_list 对 a1 进行更新,更新后的值为 "new123";dict_list 对 b1 进行更新,更新后的值为 "bbb123"。
>>> dict_list
这个结构包含两个键值对,一个键是 'a1',对应的值是 'new123';另一个键是 'b1',对应的值是 'bbb123'。
dict_list 进行更新操作,将键值对 ("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 对 a1 进行更新,更新后的值为 "new123";dict_list 对 b1 进行更新,更新后的值为 "bbb123"。
dict_list 对 ("b1","bbb123") 进行更新操作。
list和dict的实现原理
当我们去定义一个 list 时,数据会被存入内存中;当我们去定义一个 dict 时,数据也会被存入内存中。
在list中随着list数据的增大,查找时间会增大,
在 dict 中查找元素时,不会因为 dict 的增大而增大。
所以说dict查找的性能远大于list。
那么,为什么在 dict 中查找元素时,时间会比查找 list 少呢?
dict背后实现原理是哈希表(hash),其特点是:
dict 的 key 必须是可以 hash 的,set 的值也必须是可以 hash 的。
也就是说,不可变对象都是可哈希的。例如 str(字符串)、frozenset(不可变集合)、tuple(元组)。
如果是我们自己实现的类,那么我们能够在这个类里面添加__hash__。如此一来,我们的对象就会成为可 hash 对象。
dict 的内存花销比较大,然而它的查询速度却很快,像自定义对象以及 python 内部的对象等都是通过 dict 进行包装的。
3、dict的存储顺序和元素添加顺序有关。
4、添加数据有可能改变已有数据的顺序。
表元(列表中的元素)若小于三分之一,就会去重新申请空间。在重新分配内存的过程中,有可能会重新改变顺序。
字典与列表dict和list
字典通过偏移量直接寻址。
查找原理大致步骤如下,原谅我不会画图:
1、计算键的散列值(哈希值)–>
2、使用散列值的一部分来定位散列表中的一个表元 -->
3、表元为空 --> 抛出keyerror
4、表元不为空 -->
5、判断键是否相等 -->
如果是 --> 返回表元里的值
如果否,表示散列冲突 -->
6、使用散列值的另一部分来定位散列表中的另一行 -->
7、表元为空 -->
8、返回前面第3步骤继续循环
set集合和frozenset集合
1、set集合是可变集合,可以添加,可以删除。
也不记录元素的位置。
frozenset 集合具有不可变性。它不能进行添加操作。并且,一旦被创建,就无法进行删除操作。
frozenset 能够充当字典的 key 。frozenset 还能够成为其他集合的元素 。
他们特点都是无序,不能重复的,如:
set集合是无序且不能重复的:
>>> s=set('abcdcee')
>>> s
包含 'd'、'e'、'b'、'a'、'c'
set集合可以添加:
>>> s.add('g')
>>> s
包含“d”“e”“b”“a”“c”“g”。
frozenset集合也是是无序且不能重复的:
定义了一个名为 ss 的冻结集合,集合中的元素为字符串 '123332' 。
>>> ss
frozenset 包含了 '3'、'1' 和 '2' 这三个元素。frozenset 中的元素有 '3'、'1' 以及 '2'。'3'、'1' 和 '2' 构成了 frozenset。frozenset 由 '3'、'1' 和 '2' 组成。
注意,frozenset 集合不存在 add 方法,这意味着不能对其进行添加操作。
通过update来给set集合添加集合:
>>> ss=set('zyxzce')
>>> ss
该集合包含 'e'、'z'、'y'、'x'、'c'。
>>> s.update(ss)
>>> s
g 存在于这个集合中。
difference可以查看集合之间的区别:
>>> s.difference(ss)
“d”也包含在内。
list和dict的类继承
list和dict本身也是类。
在我们定义类的时候,通常不建议继承list和dict。
在某些情况下,用 C 语言编写的 dict 不会调用我们自定义的重新覆盖的方法。
如果实在要继承,可以用UserDict,如:
存在一个类叫 UserDict,它来自于 collections 模块。
class MyDict(UserDict):
在这个类的实例中,当使用方括号进行赋值操作时,即通过 self[key] = value 的形式,会触发这个特殊方法 __setitem__ 的执行。它用于设置指定键 key 对应的值为 value 。
super() 执行设置项操作,将键 key 对应的项设置为值 value 乘以 2 的结果
mydict = MyDict(a=1)
不建议的用法,这里只是顺带一提。