函数
函数的传参
关键字参数
函数调用时,指定参数的名称,即为关键字参数
- 允许传入0个或者多个含参数名的参数
- 关键字参数必须放在普通参数的后面
例:
def abc(x,a,b):
print(x)
print(a)
print(b)
abc(100,b=4,a=2) #其中a,b作为关键字参数可以随意调换位置,
#但x作为位置参数必须在关键字参数前面
结果:
100
2
4
命名关键字参数
限定后边的参数必须是以关键字形式传参
例:
def abc(a,b,*,c,d): #*后边的参数必须为关键字形参
print(a)
print(b)
print(c)
print(d)
abc(1,2,c = 3,d = 4)
结果:
1
2
3
4
可变参数
可变参数:传入的形参个数是可变的。
1、*参数:常见的*args,args变量指向一个tuple对象
自动接收所有的未匹配的位置参数,到一个tuple对象里
例:
def abc(a,*b):
print(a)
print(b)
abc(11)
abc(11,12,13,14,344)
结果:
11
() #可变参数无传参时默认空元组
11
(12, 13, 14, 344)
练习:
如:求一组数字的平方和,参数个数不确定
1、用列表或者元组-------但是调用时,需要先组成列表或者元组
2、可变参数
def calc(*numbers):
sum = 0
for n in numbers:
sum += n * n
print(sum)
calc(1,2,3,4)
结果:
30
如果要传进的是元组或者列表:
在元组或者列表前面添加(*num):即把num这个list的所有元素作为可变参数传进去
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
print(sum)
num = [1,2,3,4]
calc(*num)
结果:
30
2、**参数:所有未匹配的未知参数存储到一个字典里边去
**kwargs
例:
def abc(a,**b):
print(a)
print(b)
abc(10)
abc(10,name="zs") #必须以关键字参数的形式传入,才能以键值对的形式传出
结果:
10
{} #无传参,默认空字典
10
{'name': 'zs'}
python参数的解包
参数类型是字符串、列表、元组、集合、字典的时候,可以解包
传递实参时,可以在序列类型的参数前边添加*
*自动将序列中的元素依次作为参数传递
例:
def abc(a, b, c):
print(a)
print(b)
print(c)
abc(*"123")
abc(*[4,5,6])
结果:
1
2
3
4
5
6
注意:字典有点特殊
若要取出字典里的值时(**),必须保证字典的键与函数的传入形参相同,否则会报错
但若只是取出字典里的键时(*),不需要使字典的键与函数的传入形参相同
字典例:
def abc(a, b, c):
print(a)
print(b)
print(c)
d = {
"a" : "zs",
"b" : 18,
"c" : "python"
}
abc(*d) #一个解包是取出字典里的键
abc(**d) #两个解包是取出字典里的值
参数解包与可变参数一起用
例:
def abc(a,*args):
print(a)
print(args)
abc(100,(1,2,3)) #传入元组
abc(100,*(1,2,3))
结果:
100
((1, 2, 3),)
100
(1, 2, 3)
函数递归
我们先来讲一下函数调用函数
函数调用函数
例:
def fun_01():
print("11111111111")
def fun_02():
print("22222222222222")
fun_01()
fun_02()
结果:
22222222222222 #先调用2再调用1
11111111111
递归的定义
如果一个函数内部调用了自己本身,那么这个函数就是递归函数
递归在使用时,注意防止栈溢出。栈的大小是有限的,如果递归调用次数太多,会导致栈溢出
例:
简单的死递归
def fn():
print("我是递归函数")
fn()
fn() #死递归
结果:
File "D:\python\Day07\10.10\代码\10-函数递归.py", line 48
a = fibonacci(1000)jiu
^^^
SyntaxError: invalid syntax
因为递归函数必须要有一个出口
如果没有一般计算机递归1000次会报错
当然,我们也可以简单的检查一下我们的递归限制
方法:
import sys
a = sys.getrecursionlimit()
print(a)
结果:
1000
或在终端上:
练习1:
求阶乘
举例:9!
9!=8!*9
9!=7!*8*9
。。。
9!=1*2*3*4*5*6*7*8*9
所以:
n!=(n-1)!*n
递归出口:1
def fact(n):
if n == 1:
return 1
else:
return fact(n - 1) * n
a = fact(3)
print(a)
结果:
6
但fact(1000):会报错
因为超过了计算机的递归限制,造成栈溢出
尾递归:为了解决递归调用栈溢出的方法。
调用函数时,调用自身本身,并且,return语句不能包含表达式。编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
def fact(n):
return fact_iter(n, 1)
def fact_iter(num, product):
if num == 1:
return product
return fact_iter(num - 1, num * product)
遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。
练习2:
编写一个递归函数 fibonacci(n),用于计算斐波那契数列的第 n 个数字
斐波那契数列的定义是:前两个数是 0 和 1,后续的每个数都是前两个数之和
例:1 1 2 3 5 8 13 21
def fibonacci(n):
if n == 1 or n == 2: #或n <= 2
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)
a = fibonacci(6)
print(a)
结果:
8