将函数里面的数据传递到函数外面
初学者怎么确定需不需要返回值:
看函数的功能完成后要不要产生新的数据
函数声明时,函数体中,
return后面的值就是函数的返回值
若没有return,函数返回None
写法 | 说明 | 作用 |
---|---|---|
return | 关键字 只能写到函数体里 |
确定函数的返回值 结束函数 |
执行函数体的时候如果遇到return,函数直接结束,同时将return后面的值作为返回值返回
def sum_int(num1: int, num2: int):
return num1 + num2
获取函数调用表达式的值即可
例:用 3) 中的函数
result = sum_int(5, 2) + 2
print(result) # 结果:9
注:函数调用表达式就是函数调用语句
普通数据能做的事函数调用表达式就能做
上例子中,sum_int(5, 2) 的返回值是7,所以在语句中,和7的作用一模一样,可以直接进行运算
day9中的函数调用过程没有涉及到返回值,这里完善一下
a. 回到函数声明位置
b. 传参 - 保证每个参数都有值
c. 执行函数体
d. 执行完函数体确定返回值
看执行完函数体的时候有没有遇到return
如果遇到了return,后面的值就是返回值
没有遇到就返回None
e. 回到函数调用的位置
(这个时候函数调用表达式的值才是函数的返回值)
函数的调用过程是一个压栈的过程
调用函数的时候系统会自动在栈区间为这个函数申请一个专用的内存区域,专门用来保存在函数中声明的变量和产生的数据
注:形参也是声明在函数中的变量
当函数结束的时候,这个内存区域会自动释放
销毁前会将返回值扔出来
即变量可以使用的范围
python: 没有声明在函数中或者类中的变量都是全局变量
全局变量从声明开始到文件结束任何地方都可以使用
for b in range(4):
c = 100
pass
print(b, c) # 结果是3 100 这里b、c都是全局变量
声明在函数中的变量就是局部变量
(形参也是局部变量)
作用域:从声明开始到函数结束
def func2(aa):
pass
func2(100)
print(aa) # 报错,NameError,aa没有被定义
ps:python里,函数中还能声明函数
global和nonlocal这两个关键字只能在函数体中使用
a = 100
def func4():
a = 200
print('函数中', a)
func4()
print('函数外', a)
# 结果:
# '函数中' 200
# '函数外' 100
出现上面这个现象的原因是:
a = 100 的这个a是全局变量
函数中,a = 200 的这个a是函数中的局部变量,是一个新的变量
函数结束时,值是200的局部变量a在内存里被释放
而原来的值是100的a还是原来的a
a = 100
def func4():
global a # 这个单独占一行!!!
a = 200
print('函数中', a)
func4()
print('函数外', a)
# 结果:
# '函数中' 200
# '函数外' 200
写法 | 说明 |
---|---|
global 变量 变量 = … |
函数中,在变量赋值前, 在函数中声明此变量为全局变量 |
使用场景:
在局部的局部中,修改局部的值
def func5():
a = 100
def func6():
a = 200 # 这里也不行
print(a)
func6()
print(a)
# 结果:200 100
在func6中,修改a的值也不行
因为a=200的a是func6的局部变量
同global一样,只是nonlocal在局部中使用
def func5():
a = 100
def func6():
nonlocal a
a = 200 # 这里可以
print(a)
func6()
print(a)
func5()
# 结果:200 200
*但是nonlocal不能声明,只能修改!!!
def func5():
a = 100
def func6():
nonlocal b # 这里报错
b = 200
print(a)
func6()
print(a)
写法 | 说明 |
---|---|
nonlocal 变量 变量 = … |
作用: 在子函数中,修改母函数的局部变量的值 |
nonlocal几乎不用,因为函数中声明函数已经很少见了,在这种情况下还有在子函数中修改母函数的局部变量,更罕见了
没有名字的函数
匿名函数还是函数,普通函数中,除了声明的语法以外,其他常用语法基本都适用于匿名函数
注:不支持普通函数中形参的参数类型说明
lambda 参数列表:返回值
写法 | 说明 |
---|---|
lanmbda | 关键字,固定写法 |
参数列表 | 形参:参数1,参数2,… |
: | 固定写法,不产生缩进 |
返回值 | 相当于普通函数的return语句 |
相当于:
def (参数列表):
return 返回值
随堂练习:
用匿名函数实现两个数求和
func1 = lambda num1, num2: num1 + num2 # 声明
print(func1(10, 20)) # 结果:30
因为匿名,所以没法直接调用,这里暂时用一个变量去接
随堂练习:
写一个匿名函数判断指定的年是否是闰年
loop_year = lambda year: (year % 4 == 0 and year % 100 != 0) or year % 400 == 0
在声明函数时调用函数本身的函数
即在声明的时候调用自己
def func1():
func1() # 报错
因为每次执行函数都会压栈,无限压栈内存怎么都不够
递归可以实现循环效果
原则上,除了死循环,其他的循环用递归都可以实现
递归比循环会消耗多的多的内存空间
使用递归的套路:
a. 设置临界值 - 循环结束的条件(保证函数在临界值结束)
b. 找关系 - 找f(n)和f(n-1)的关系
c. 假设函数的功能已经实现,通过f(n-1)去实现f(n)的功能
栗子:写一个递归函数,计算1+2+3+…+N
def sum_num(n: int):
# 找临界值
if n == 1:
return 1
# 找关系
"""
f(n): 1+2+3+...+n
f(n-1): 1+2+3+...+n-1
f(n) = f(n-1) + n
"""
# 用f(n-1)实现f(n)的功能
return sum_num(n - 1) + n
n=5时的实现过程:
这里的 yt_sum() 和上面的 sum_num() 一样
随堂练习:
写一个递归函数,求斐波那契数列的第n个数
1,1,2,3,5,8,13,21…
def fibonacci(n: int):
# 找临界值
if n == 1 or n == 2:
return 1
# 找关系
# f(n) = f(n - 1) + f(n - 2)
# 用f(n-1)实现f(n)的功能
return fibonacci(n - 1) + fibonacci(n - 2)
练习:
写一个递归函数:
n = 4
*
**
***
****
自己做的:
def star(n: int):
if n == 1:
return '*'
return star(n - 1) + '\n' + '*' * n
老师答案:
def print_star(n):
if n == 1:
print('*')
return
print_star(n - 1)
print(n * '*')
完善昨天的作业,尝试写出交互式学生管理系统
学生管理系统见day10的周末篇