定义函数
def < name >(arg1, arg2, ....argN):
< statements >
定义一个函数的几个基本规则:
- 函数代码块以 def 开头,后接函数标识符名称与圆括号;
- 所有传入的参数和自变量都必须放在括号内,可在括号内定义参数;
- 函数内容以冒号开始,并且需要缩进;
- return [ 表达式 ] 结束函数,选择性的返回一个值给调用方,不带表达式的return相当于返回None
- 对于函数的定义来说:使用return语句可以向外提供该函数执行的一些结果
函数的参数
def mark(a,b=1,*c,**d):
print(f'a = {a}, b = {b} ,c = {c} , d = {d}')
mark(1,5)
mark(1,5,9,"p")
mark(c=1,a=5)
mark(1,No = 18)
结果如下
a = 1, b = 5 ,c = () , d = {}
a = 1, b = 5 ,c = (9, 'p') , d = {}
a = 5, b = 1 ,c = (1) , d = {}
a = 1, b = 1 ,c = () , d = {'No': 18}
调用函数时,可以使用的5种类型的参数:
- 必须参数(位置参数) a
必须参数在传入时必须以正确的顺序传入,调用时数量必须和声明时一样 - 关键字参数 mark(c=1,a=5)
使用关键字参数允许调用函数时参数的顺序与声明时不一致,解释器能够用参数名匹配参数值 - 默认参数 b
默认参数是在定义函数时,给参数一个默认值;调用函数时,如果没有传递参数,就会使用默认参数默 - 可变参数 *c,**d
加了 * 或者 ** 的变量名会存放所有未命名的变量参数;如果在调用函数时没有指定参数,就是一个空元组(或空字典);
*与 **的区别在于: * 一般储存未命名的非关键字参数(元组结构), **主要储存未命名的关键字参数(字典结构) - 组合参数 在定义函数时同时使用上述多种类型的参数
如示例,在定义参数时如果使用多种类型的参数,需遵从一定的顺序:
必须参数,默认参数,可变参数,关键字参数
全局变量与局部变量
- 局部变量
在函数内定义的变量只能在函数内部被引用,这个变量的作用于是局部的(函数内) - 全局变量
在函数外,一段代码最开始赋值的变量可以被多个函数引用,这就是全局变量
num = 100
def func():
num = 200
return num
print(num + 1)
print (func() + 1)
结果
101
201
在函数中使用某个变量时,如果该变量同时有局部变量和全局变量(变量名相同),默认引用局部变量;
如果需要在 函数中将某个变量定义为全局变量,需要在被定义的变量前加上关键字 global(global num)
(函数中)返回函数
- 闭包:如果在一个函数内部中对外部函数(非全局作用下)的变量进行引用,内部函数就被认为是闭包(closure)
def sum_late(*arg): # 定义一个序列求和函数
def clac_sum(): # 在函数内再定义一个函数
ax = 0
for n in arg: # 对函数sum_late的参数arg进引用
ax = ax + n
return ax # 返回变量ax,以得到求和值
return clac_sum #函数sum_late执行的结果是返回函数clac_sum
print(sum_late(1,2,3,4)) # 将参数直接传入sum_late函数,得到一个字符串(就是函数sum_late)
orc = sum_late(1,2,3,4)
print(orc()) # 写法等同于print(sum_late(1,2,3,4)())
结果如下
<function sum_late.<locals>.clac_sum at 0x00D13F18>
10
递归函数
如果一个函数在内部调用自身,这个函数就称作递归函数
def recurision():
return recurision()
按照计算n的求和来说
假如:add(n) = 1+2+3+4+…+n ,那么add(n) = add(n-1) + n
def add(n):
if n == 1:
return 1
else:
return add(n-1) + n
print(add(100))
对于函数add(),当传入参数时,执行的步骤如下(例:传入5)
add(5) = add(4) + 5
=( add(3) + 4) + 5
=((add(2)) + 3 + 4) + 5
=((add(1) + 2) + 3) + 4) + 5
= 1 + 2 + 3 + 4 + 5
= 15
尾递归优化
- 在计算机中,函数的调用是通过栈(stack)这种数据结构实现的;
每当进入一个函数调用,栈就会加一层浅栈;每当函数返回,减一层浅栈;
栈的大小有限,一旦此种方式调用时传入的参数过大(递归调用的次数过多)会导致栈溢出。
尾递归优化就是解决此类问题的方案之一
具体定义:在函数返回时,调用函数本身,并且return语句不能包含表达式
def dda(n,m):
if n == 1:
return m
else:
return dda(n - 1,m + n)
print(dda(100,1))
对于函数dda(),当传入参数时,执行的步骤如下(例:传入5,1)
dda(5,1) = dda(4,6) = dda(3,10) = dda(2,13) = dda(1, 15) = 15
每一个步骤都是函数dda()调用然后返回的结果,始终只占用一层浅栈