Python内置的核心数据类型如下表所示。
对象类型 | 分类 | 是否可变 |
---|---|---|
数字 | 数值 | 否 |
字符串 | 序列 | 否 |
元组 | 序列 | 否 |
列表 | 序列 | 是 |
集合 | 集合 | 是 |
字典 | 映射 | 是 |
在使用的时候,需要我们注意的是python中的一切变量都是引用赋值的,除非你显示进行复制操作。变量本身没有数据类型,有数据类型的是对象。变量就是一个void *
类型的指针。
因为Python中的复合对象类型可以嵌套任意的对象类型,因此它们几乎可以表示任意的复杂数据。
嵌套对象在内部实际上被表示为指向不同内存区域的指针。
通常情况下,变量的引用赋值是符合我们预期的。如果你确实需要复制对象,那么可以使用下面的方法来实现。
浅拷贝是指只对顶层进行复制操作,嵌套在内部的数据结构不会被复制。
>>> l = [1, 2, 3]
>>> l2=l[:] # 复制
>>> l3=l[::] # 复制
>>> l4=l # 引用
>>> id(l)
138078511943584
>>> id(l2)
138078511943344
>>> id(l3)
138078511943184
>>> id(l4)
138078511943584
可以看到l和l4的id值是相同的,而使用不带有任何参数的分片进行赋值操作,结果是引用赋值。因此l2和l3的id值是新的,和l不相同。
不仅仅复制顶层,也会复制嵌套的数据结构。这将是完整的,完全的独立的复制。可以使用标准库的copy模块来做到深拷贝。
>>> import copy
>>> L1 = [1,2, [1,2]]
>>> L2 = copy.deepcopy(L1)
>>> L2
[1, 2, [1, 2]]
>>> id(L1[-1])
130018979552256
>>> id(L2[-1])
130018978665408
可以看到,使用copy.deepcopy()方法复制对象,会将嵌套的数据结构也进行复制。
深拷贝是极少出现的情况,如果你需要使用深拷贝,必须要慎重考虑。
比较也是非常重要的一部分内容。因为对于不同分类而言,比较的方式是不同的。
下面是一个例子,其中的a列表包含了它自己的引用。
>>> a = [1]
>>> a.append(a)
>>> a
[1, [...]]
>>> b = copy.deepcopy(a) # 深拷贝a
>>> b
[1, [...]]
>>> a == b # 对比a和b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RecursionError: maximum recursion depth exceeded in comparison
>>>
我们深拷贝了a,但是并没有触发堆栈溢出,这是因为深度拷贝函数 deepcopy 中会维护一个字典,记录已经拷贝的对象与其 ID。拷贝过程中,如果字典里已经存储了将要拷贝的对象,则会从字典直接返回。
# python3.8中的deepcopy源码
def deepcopy(x, memo=None, _nil=[]):
"""Deep copy operation on arbitrary Python objects.
See the module's __doc__ string for more info.
"""
if memo is None:
memo = {} # 空字典
d = id(x) # 查询x的id
y = memo.get(d, _nil) # 查询字典中是否存在id
if y is not _nil: # 如果存在这个id,直接返回对应的值
return y
cls = type(x)
copier = _deepcopy_dispatch.get(cls)
if copier is not None:
y = copier(x, memo)
else:
if issubclass(cls, type):
y = _deepcopy_atomic(x, memo)
else:
copier = getattr(x, "__deepcopy__", None)
if copier is not None:
y = copier(memo)
else:
reductor = dispatch_table.get(cls)
if reductor:
rv = reductor(x)
else:
reductor = getattr(x, "__reduce_ex__", None)
if reductor is not None:
rv = reductor(4)
else:
reductor = getattr(x, "__reduce__", None)
if reductor:
rv = reductor()
else:
raise Error(
"un(deep)copyable object of type %s" % cls)
if isinstance(rv, str):
y = x
else:
y = _reconstruct(x, memo, *rv)
# If is its own copy, don't memoize.
if y is not x:
memo[d] = y
_keep_alive(x, memo) # Make sure x lives at least as long as d
return y
在执行 == 操作时,因为a中存储了自身的引用,会无限的递归与b比较,从而造成RecursionError异常,因为最大递归深度有一定的限制。