定义函数
2021-7-3
| 2023-8-6
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
Property

 
Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后在缩进块中编写函数体,最后用return语句返回返回值
如果已经把my_abs()的函数定义保存为abstest.py文件了,那么可以在该文件的当前目录下启动Python解释器,用from abstest import my_abs来导入my_abs()函数
 

空函数

如果想定义一个什么事也不做的空函数,可以用pass语句:
 

参数检查

修改一下my_abs的定义,对参数类型做检查,只允许整数和浮点数类型的参数。数据类型检查可以用isinstance()实现:
添加了参数检查后,如果传入错误的参数类型就可以抛出一个错误
 

函数返回值

一个函数有没有返回值,就看return只有return才有返回值。
函数中可以有多个return语句,但只要执行到一个return语句,那么就意味着这个函数的调用完成。
函数执行完毕也没有return语句时,自动return None
 

返回多个值

 
其实这只是一种假象,Python函数返回的仍然是单一值:
原来返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。
 
 

局部变量和全局变量

局部变量

局部变量是定义在函数内部的变量。
不同的函数可以定义相同名字的局部变量,但是各用个的不会产生影响。局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储。
 

全局变量

如果一个变量,既能在一个函数中使用,也能在其他函数中使用,这样的变量就是全局变量
 

修改全局变量

修改全局变量:使用global在变量名前进行声明
 
 

递归函数

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示:
fact(n)可以表示为n x fact(n-1),只有时需要特殊处理。fact(n)用递归的方式:
递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
 
使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以递归调用的次数过多会导致栈溢出:
 

尾递归

解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
尾递归是指:在函数返回的时候,调用自身本身,并且return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
上面的fact(n)函数由于return n * fact(n - 1)引入了乘法表达式,所以就不是尾递归了。要改成尾递归方式,需要多一点代码,主要是要把每一步的乘积传入到递归函数中:
可以看到,return fact_iter(num - 1, num * product)仅返回递归函数本身,num - 1num * product在函数调用前就会被计算,不影响函数调用。
 
fact(5)对应的fact_iter(5, 1)的调用如下:
尾递归调用时,如果做了优化,栈不会增长,因此,无论多少次调用也不会导致栈溢出。
遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。
 
  • Python
  • 内置函数函数的参数
    目录