共计 1542 个字符,预计需要花费 4 分钟才能阅读完成。
导读 | 赋值,值相同,内存地址相同–函数参数传递。浅拷贝,值相同,内存地址不同。 |
拷贝第一层内存地址的引用。第一层元素为可变元素。拷贝过的引用会跟着发生变化。否则不发生变化
import copy | |
a = [[], 'hello', 'world', {}] | |
b = a | |
c = copy.copy(a) | |
a | |
[[], 'hello', 'world', {}] | |
b | |
[[], 'hello', 'world', {}] | |
c | |
[[], 'hello', 'world', {}] | |
a[0].append('hi') | |
a.append('小明') | |
a | |
[['hi'], 'hello', 'world', {}, '小明'] | |
b | |
[['hi'], 'hello', 'world', {}, '小明'] | |
c | |
[['hi'], 'hello', 'world', {}] |
浅拷贝只是拷贝第一层地址的引用。
函数参数传递–引用
class T: | |
def __init__(self, passengers=[]): | |
self.passengers = passengers | |
def pick(self, v): | |
self.passengers.append(v) | |
def remove(self, v): | |
self.passengers.remove(v) | |
t1 = T() | |
t1..pick('hi') | |
t2 = T() | |
t1.passengers | |
t2.passengers | |
# ['hi'] | |
# ['hi'] |
出现问题的原因是:实例化对象时没有指定 passengers 实例会共享列表
问题根源:默认值在定义函数时计算(通常在加载模块时)__init__检查参数为 None 赋值一个列表。否则示例化时共享列表。
防御可变函数带来的影响
如果函数接受可变参数。应该谨慎考虑调用方法是否期望修改传入的参数。
例如:参数是一个字典,而且在处理的过程中需要修改它。那么,你要考虑!!!函数外部是否会收到影响
# passengers 避免受到影响 | |
class Test: | |
def __init__(self, passengers=None): | |
if passengers is None: | |
self.passengers = [] | |
else: | |
# 深拷贝 | |
self.passengers = list(passengers) | |
def pick(self, v): | |
self.passengers.append(v) | |
def remove(self, v): | |
self.passengers.remove(v) | |
def test(passengers=None): | |
if passengers is None: | |
passengers = [] | |
else: | |
# 深拷贝 | |
passengers = copy.deepcopy(passengers) |
函数传递的方式
人们经常说:参数按值传递,但是这里是值得引用。这么说没有错,但是会引起误解。因为,在旧式语言中,最常用的参数传递方式有根据值传递(函数得到参数的副本)和按照引用传递(函数得到参数的指针)。Python 中函数得到参数的副本(可以理解为浅拷贝),但是参数始终是引用。因此,参数是一个可变对象,那么对象可能被修改,但是对象的标识(内存地址)不变。此外,因为函数得到的参数是引用的副本。所以重新绑定对函数的外部没有影响。
简单理解
def func(x=[[], 1]): | |
print(x) | |
x.append('a') | |
print(x) | |
x[0].append('b') | |
print(x) | |
# func 参数时一个可变类型 | |
func() | |
func() | |
# 第一次调用 x =[['b'], 1, 'a'] | |
# 此时在 func(x=[['b'], 1, 'a']) 不在是 func(x=[[], 1])。有点类似 在函数外部定义的 x=[[], 1] |
正文完
星哥玩云-微信公众号
