python中的参数传递既不是值传递,也不是引用传递,而是赋值传递,或者说叫对象的引用传递,不是指向一个具体的内存地址,而是指向一个具体的对象
- 对象是可变的,当其改变时,所有指向这个对象的变量都会改变
- 如果对象不变,简单的赋值只能改变其中一个变量的值,其余变量不受影响
== 和 is
1.==
是值得比较,is
是id的比较,is
的速度往往优于==
(is的操作符无法重载,只是简单地获取id进行比较,而==操作符则会递归地遍历对象的所有值),被赋值的变量与赋值的变量id相等
2.创建一个-5到256范围内的整形数字时,python会从这个数组中返回相对应的引用,python都会从数组中返回相对引用,而不是开辟一个新的内存空间python
浅拷贝
1.浅拷贝对于完全不可变类型,不会拷贝仅仅只会指向,例如
import copy
# 可变对象,浅拷贝生效
a = [1, 2, 3]
b = copy.copy(a)
print(a is b) # False
# 不可变对象,浅拷贝不生效,仅仅指向
a = (1, 2, 3)
b = copy.copy(a)
print(a is b) # True
2.浅拷贝对象对于可变对象类型,只对顶层进行拷贝,如果有多层中有可变对象类型则只是引用,及里面的元素是原对象中子对象的引用
import copy
# 可变对象,可变对象[1, 2, 3]和不可变对象(1, 2, 3)
a = {"a": [1, 2, 3], "b": (1, 2, 3)}
b = copy.copy(a)
b["c"] = 100
print(a) # {'a': [1, 2, 3], 'b': (1, 2, 3)}
print(b) # {'a': [1, 2, 3], 'b': (1, 2, 3), 'c': 100}
b["a"].append(4)
print(a) # {'a': [1, 2, 3, 4], 'b': (1, 2, 3)}
print(b) # {'a': [1, 2, 3, 4], 'b': (1, 2, 3), 'c': 100}
b["b"] += (4, 5)
print(a) # {'a': [1, 2, 3, 4], 'b': (1, 2, 3)}
print(b) # {'a': [1, 2, 3, 4], 'b': (1, 2, 3, 4, 5), 'c': 100}
3.分片表达式相当于一个浅拷贝
深拷贝
1.对于可变对象的深拷贝,是对一个对象所有层次的递归拷贝
2.对于完全不可变对象类型,不会拷贝仅仅只会指向
3.对于可变对象存在对自身的循环引用,深拷贝也不会StackOverflow,因为深拷贝时会维护一个字典,记录已拷贝对象和id,如果id存在直接返回
import copy
x = [1]
x.append(x)
print(x)
y = copy.deepcopy(x)
print(x == y) #抛错:RecursionError: maximum recursion depth exceeded in comparison
源码
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)
y = memo.get(d, _nil)
if y is not _nil:
return y