Python参数传递
目录
1.什么是参数的传递
2.传递不可变对象的引用
不可变对象:int、float、字符串、元组、布尔值。
2.1 传递不可变对象的引用的底层逻辑
关键:把
a
\color{red}{a}
a 的
i
d
\color{orange}{id}
id 传给
n
\color{purple}{n}
n ,
n
\color{purple}{n}
n 也指向了
a
\color{red}{a}
a 所指向的 int 对象,但由于 int 对象不可改变,因此执行n=n+2
时,会创建一个新对象存储 “n+2” 的计算结果,再让
n
\color{purple}{n}
n 指向这个新的计算结果对象。但原本
a
\color{red}{a}
a 和
n
\color{purple}{n}
n 共同指向的 int对象未改变,现在
n
\color{purple}{n}
n 不指向原本的 int对象了,又由
a
\color{red}{a}
a 单独指向 int对象。
2.1.1 传递不可变对象的底层步骤:
①栈中创建全局变量
a
\color{red}{a}
a,堆中创建了一个
v
a
l
u
e
\color{orange}{value}
value 为
100
\color{green}{100}
100 的 int对象。int对象
i
d
\color{orange}{id}
id 给了 全局变量
a
\color{red}{a}
a,
a
\color{red}{a}
a 指向该列表对象。
②def f1(n):
函数定义。
栈中产生全局变量
f
1
\color{red}{f1}
f1 ,堆中产生函数对象,并将函数对象的
i
d
\color{orange}{id}
id 给
f
1
\color{red}{f1}
f1。
此时
f
1
\color{red}{f1}
f1 指向函数对象。参数
n
\color{purple}{n}
n 尚未用到。
③f1(a)
调用函数,传递参数
a
\color{red}{a}
a —>
n
\color{purple}{n}
n
栈中产生一个栈帧,在栈帧中产生局部变量
n
\color{purple}{n}
n,由于实参
a
\color{red}{a}
a 传给了形参
n
\color{purple}{n}
n,此时局部变量
n
\color{purple}{n}
n 也指向了
a
\color{red}{a}
a 所指向的 int对象,此时
a
\color{red}{a}
a 和
n
\color{purple}{n}
n 共同指向 int对象。
④n=n+200
计算结果并创建新对象保存结果,将
n
\color{purple}{n}
n 指向新对象
由于 int对象是不可变对象,因此虽然
n
\color{purple}{n}
n 此时直接指向了int对象也不能在int对象上直接修改。于是现在堆中新建一个 int对象,将n+200
的计算结果保存到对象中作为
v
a
l
u
e
\color{orange}{value}
value,再让
n
\color{purple}{n}
n 指向这个新对象。随后,又只有
a
\color{red}{a}
a 指向原本的 int对象,
n
\color{purple}{n}
n 不再指向原本的 int对象而是指向了新对象,所以
n
\color{purple}{n}
n 在函数中的操作就与原本的 int对象没有关系了。
简单测试:
浅拷贝
①test01()
参数传递
a
\color{red}{a}
a -->
m
\color{purple}{m}
m
a
\color{red}{a}
a 和
m
\color{purple}{m}
m共同指向元组对象。
②m[2][0] = 888
修改元组对象的第三个子对象(即列表对象)的第一值为
i
n
t
(
888
)
\color{green}{int(888)}
int(888) 。
最终,
a
\color{red}{a}
a 和
m
\color{purple}{m}
m 共同指向的元组对象的第二个子对象(列表对象)的第一个元素被修改为
i
n
t
(
888
)
\color{green}{int(888)}
int(888) 。
3.传递可变对象的引用
可变对象:列表、字典、自定义的其他可变对象。
3.1 传递可变对象的引用的底层逻辑
关键:由于列表是可变对象,那么把
b
\color{red}{b}
b 列表
i
d
\color{orange}{id}
id 给了栈帧里的局部变量
m
\color{blue}{m}
m,
m
\color{blue}{m}
m 也指向了列表对象。
于是
m
\color{blue}{m}
m 可以对列表进行直接操作。
m
\color{blue}{m}
m 消失后,操作结果还在。
3.1.1 传递可变对象的底层步骤:
①栈中创建全局变量
b
\color{red}{b}
b,堆中创建了一个列表对象,包含
10
\color{green}{10}
10、
20
\color{green}{20}
20两个值。列表对象
i
d
\color{orange}{id}
id 给了 全局变量
b
\color{red}{b}
b,
b
\color{red}{b}
b 指向该列表对象。
②def f2(m):
函数定义。
栈中产生全局变量
f
2
\color{red}{f2}
f2 ,堆中产生函数对象,并将函数对象的
i
d
\color{orange}{id}
id 给
f
2
\color{red}{f2}
f2。
此时
f
2
\color{red}{f2}
f2 指向函数对象。参数
m
\color{purple}{m}
m 尚未用到。
③f2(b)
调用函数,传递参数
b
\color{red}{b}
b —>
m
\color{purple}{m}
m
栈中产生一个栈帧,在栈帧中产生局部变量
m
\color{purple}{m}
m,由于实参
b
\color{red}{b}
b 传给了形参
m
\color{purple}{m}
m,此时局部变量
m
\color{purple}{m}
m 也指向了
b
\color{red}{b}
b 所指向的列表对象,此时
b
\color{red}{b}
b 和
m
\color{purple}{m}
m 共同指向列表对象。
④m.append(30)
在列表对象中添加了一个新元素
i
n
t
(
30
)
\color{green}{int(30)}
int(30)
由于
m
\color{purple}{m}
m 已经指向了列表对象,因此可以直接对列表对象进行操作。于是成功在
b
\color{red}{b}
b 和
m
\color{purple}{m}
m 共同指向的列表对象上添加了元素
i
n
t
(
30
)
\color{green}{int(30)}
int(30)。
执行完函数后,栈内的栈帧消失,局部变量
m
\color{purple}{m}
m 消失,此时又只有
b
\color{red}{b}
b 指向列表对象。
此时栈堆情况:
b
\color{red}{b}
b 指向的列表对象已经有了三个元素:
10
\color{green}{10}
10、
20
\color{green}{20}
20、
30
\color{green}{30}
30 。
简单测试: