返回值return
还可以结束函数的运行
def my_avg(a, b):
return (a + b) / 2
c = my_avg(20, 30)
print(c)
25.0
def add(a, b):
print("计算两个参数{0},{1}的和:{2}".format(a, b, (a + b)))
return a + b
def text02(x, y, z):
return [x ** 2, y ** 2, z ** 2]
c = add(20, 30)
print(c)
d = text02(2, 3, 4)
print(d)
50
[4, 9, 16]
局部变量全局变量
局部变量a与全局变量a是完全两个对象,函数里优先只局部变量
参数的传递_传递可变对象_内存分析
可变对象
a = [10, 20]
print(id(a))
print(a)
print("*****************************************")
def test01(m):
print(id(m))
m.append(300)
print(id(m)) # 由于a是可变对象,所以m地址不变
test01(a)
print(a)
2144395747912
[10, 20]
*****************************************
2144395747912
2144395747912
[10, 20, 300]
注:
- a是一个栈,相对应数据值存在堆中;m是一个栈帧,相对应数据值也存在堆中
- 如果调用函数,会启动一个栈帧m,结束后即消失
- m是局部变量,调用时m与a的地址一模一样
- 由于此处a是可变对象,所以可修改
参数的传递_传递不可变对象_内存分析
a = 100
def f1(n):
print("n:", id(n)) # 传递进来的是a对象的地址
n = n + 200 # 由于a是不可变对象,因此创建新的对象n(id不同)
print("n:",id(n)) # n已经变成了新的对象
print(n)
f1(a)
print("a:",id(a))
n: 140706869780384
n: 2288594194384 # 输出地址变了,不再是原来的n了
300
a: 140706869780384
浅拷贝和深拷贝_内存分析
浅拷贝:只拷贝对象本身,不包含该对象引用的其他对象
深拷贝:连带该对象引用的所有相关的对象(儿子孙子家庭)全拷贝
import copy
a = [10, 20, [5, 6]]
b = copy.copy(a)
print("a:",a)
print("b:",b)
b.append(30)
b[2].append(7)
print("浅拷贝……")
print("a:", a)
print("b:", b)
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6]]
浅拷贝……
a: [10, 20, [5, 6, 7]] # b中包含的下一子对象依旧是a中的,
b: [10, 20, [5, 6, 7], 30] # 改b中该对象即a中的
a = [10, 20, [5, 6]]
b = copy.deepcopy(a)
print("a:", a)
print("b:", b)
b.append(30)
b[2].append(7)
print("深拷贝……")
print("a:", a)
print("b:", b)
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6]]
深拷贝……
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6, 7], 30]
深拷贝则全部拷贝了过来,b怎么改都不会影响到a了
参数的传递_不可变对象含可变子对象_内存分析
a = (10, 20, [5, 6])
print("a:", id(a))
def test01(m):
print("m:", id(m))
m[0] = 20 # 这样会报错,元组不可变
print(m)
print("m:", id(m))
test01(a)
传递不可变对象时,如果包含的子对象是可变的,则可修改
a = (10, 20, [5, 6])
print("a:", id(a))
def test01(m):
print("m:", id(m))
m[2][0] = 888 # 改变元组内层列表元素的值
print(m)
print("m:", id(m))
test01(a)
print(a)
a: 1925259481304
m: 1925259481304 # m的id不变,仍是那个对象
(10, 20, [888, 6])
m: 1925259481304
(10, 20, [888, 6]) # a也跟随m的变化改变了
注:绿色圈圈包含的是不可修改的
参数的几种类型
位置参数
默认值参数
def test01(a, b = 10, c = 20): # 默认值参数必须位于普通位置参数后面
print(a,b,c)
test01(8,9,19) # 可通过传递新值覆盖默认值
命名参数
def f1(a, b, c):
print(a, b, c)
f1(8, 9, 10) # 位置参数
f1(c=10, a=20, b=30) # 命名参数
可变参数
指可变数量的参数
def f1(a,b,*c) # 将多个参数收集到一个元组c中
print(a,b,c)
f1(8,9,19,20) # 将19,20收集到c中
def f2(a,b,**c) # # 将多个参数收集到一个字典c中
print(a,b,c)
f1(8,9,name='celia',age=20)
def f2(a,b,*d,**c): # 注意顺序是先元组后字典
print(a,b,c,d)
f1(8,9,30,40,name='celia',age=20)
强制命名参数
可变参数后如果还要加参数,需要强制命名
def f2(*d, a, b):
print(a, b, d)
f2(8, 9, a=30, b=40)
lambda表达式和匿名函数
在这里插入代码片
eval()函数用法
可从外部传进来
递归函数_函数调用内存分析_栈帧的创建
递归函数:自己调用自己的函数,在函数内部直接或间接的自己调用自己
先执行的后调用
嵌套函数_内部函数_数据隐藏
nonlocal关键字(似global)
nonlocal声明外层局部变量内层函数想使用外层函数中的变量通常情况下,内层函数可以调用外层函数的变量,但是不能修改