Python3学习笔记05—函数之可变参数

可变参数:
在Python中,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。
例子:
给定一组数字a,b,c……,请计算a²+b²+c²+……。
由于参数个数不确定,我们首先想到的是可以把a,b,c,……作为一个list或tuple传进来,这样,函数可以定义如下:

def calc(numbers):
sum=0
for n in numbers:
sum=sum+n**2
return sum
print(calc([1,3,5,7]))
print(calc((1,2,3)))
运行结果:84 14

如果利用可变参数,调用函数的方式可以简化成这样:
calc(1,2,3) 14
calc(1,3,5,7) 84
所以我们把函数的参数改为可变参数:

#自定义可变参数在参数前边加,省去了传入list或tuple*
def calc(*numbers):
sum=0
for n in numbers:
sum=sum+n**2
return sum
print(calc(1,3,5,7))

如果已经有一个list或者tuple,要调用一个可变参数怎么办?
nums=[1,2,3]
calc(nums[0],nums[1],nums[2]) 结果 14
这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:
nums=[1,2,3]
calc(*nums) 结果 14
*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。

关键字参数:
**KW
def person(name, age, kw):
print(‘name:’, name, ‘age:’, age, ‘other:’, kw)

命令关键字参数
,命令关键字参数需要一个特殊分隔符,*后面的参数被视为命令关键字参数。
def person(name, age, *, city, job):
print(name, age, city, job)

参数组合:
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命令关键字参数,其中可变参数无法和命名关键字参数混合。
参数定义的顺序必须是:必选参数、默认参数、可变参数/命令关键字参数、关键字参数。

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
举个例子,我们来计算n!=123*……n,用函数fact(n)表示:
fact(n)=n
fact(n-1),只有n=1时需要特殊处理,于是fact(n) 用递归的方式写出来就是:
def fact(n):
if n==1:
return 1
return n*fact(n-1)
print(fact(1))
print(fact(5))
print(fact(100))

递归函数的有点时定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
**使用递归函数需要注意防止栈溢出。**在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈久会加一层栈帧,每当函数返回,栈久会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数果多,会导致栈溢出。可以试试fact(1000)。

解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。

尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样编译器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
上面的fact(n)函数由于return n*fact(n-1)引入了乘法表达式,所以就不是尾递归了。要改成尾递归方式,需要多一点代码,主要是把每一步的乘积传入到递归函数中:
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)
print(fact(5))
print(fact(1000))

尾递归调用时,如果做了优化,栈不会增长,无论多少次调用也不会导致栈溢出。
遗憾的是,大多数变成语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。

你可能感兴趣的:(python基础)