1、函数介绍
请看如下代码:
1 | print (" _ooOoo_ ") print (" o8888888o ") print (" 88 . 88 ") print (" (| -_- |) ") print (" O\\ = /O ") print (" ____/`---'\\____ ") print (" . ' \\| |// `. ") print (" / \\||| : |||// \\ ") print (" / _||||| -:- |||||- \\ ") print (" | | \\\\\\ - /// | | ") print (" | \\_| ''\\---/'' | | ") print (" \\ .-\\__ `-` ___/-. / ") print (" ___`. .' /--.--\\ `. . __ ") print (" ."" '< `.___\\_<|>_/___.' >'"". ") print (" | | : `- \\`.;`\\ _ /`;.`/ - ` : | | ") print (" \\ \\ `-. \\_ __\\ /__ _/ .-` / / ") print (" ======`-.____`-.___\\_____/___.-`____.-'====== ") print (" `=---=' ") print (" ") print (" ............................................. ") print (" 佛祖镇楼 BUG辟易 ") print (" 佛曰: ") print (" 写字楼里写字间,写字间里程序员; ") print (" 程序人员写程序,又拿程序换酒钱。 ") print (" 酒醒只在网上坐,酒醉还来网下眠; ") print (" 酒醉酒醒日复日,网上网下年复年。 ") print (" 但愿老死电脑间,不愿鞠躬老板前; ") print (" 奔驰宝马贵者趣,公交自行程序员。 ") print (" 别人笑我忒疯癫,我笑自己命太贱; ") print (" 不见满街漂亮妹,哪个归得程序员?") |
运行后的现象:
如果一个程序在不同的地方需要输出“佛祖镇楼”,程序应该怎样设计?
1 | if 条件1: 输出‘佛祖镇楼’ ...(省略)... if 条件2: 输出‘佛祖镇楼’ ...(省略)... |
如果需要输出多次,是否意味着要编写这块代码多次呢?
结论:
如果在开发程序时,需要某块代码多次,但是为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数。
2、函数定义和调用
2.1、定义
定义函数的格式如下:
1 | def 函数名(): 代码 |
示例:
1 | # 定义一个函数,能够完成打印信息的功能 def printInfo(): print ('------------------------------------') print (' 人生苦短,我用Python') print ('------------------------------------') |
2.2、调用
定义了函数之后,就相当于有了一个具有某些功能的代码,想要让这些代码能够执行,还需要调用它。
调用函数很简单,通过 函数名()
即可完成调用。
示例
1 | # 定义完函数后,函数是不会自动执行的,需要调用它才可以 printInfo() |
注意:Python 调用函数要放在定义函数后面,部分编程语言可放在前面。
2.3、文档说明
1 | def test(a,b): "用来完成对2个数求和" print("%d"%(a+b)) |
如果执行
1 | help(test) |
就能够看到test
函数的相关说明:
1 | Help on function test in module __main__: test(a, b) 用来完成对2个数求和 (END) |
2.4、函数参数
假设:现在需要定义一个函数,这个函数能够完成2个数的加法运算,并且把结果打印出来,该怎样设计?下面的代码可以吗?有什么缺陷吗?
1 | def add2num(): a = 11 b = 22 c = a+b print(c) |
为了让一个函数更通用,即想让它计算哪两个数的和,就让它计算哪两个数的和,在定义函数的时候可以让函数接收数据,就解决了这个问题,这就是函数的参数。
2.4.1、定义
示例:
1 | def add2num(a, b): c = a+b print(c) |
2.4.2、调用
以调用上面的add2num(a, b)函数为例:
1 | def add2num(a, b): c = a+b print(c) add2num(11, 22) #调用带有参数的函数时,需要在小括号中,传递数据 |
调用带有参数函数的运行过程:
2.4.3、参数顺序
1 | >>> def test(a,b): ... print(a,b) ... >>> test(1,2) 1 2 >>> test(b=1,a=2) 2 1 >>> >>> test(b=1,2) File "<stdin>", line 1 SyntaxError: positional argument follows keyword argument >>> >>> |
2.4.4、总结
- 定义时小括号中的参数,用来接收参数用的,称为 “形参”。
- 调用时小括号中的参数,用来传递给函数用的,称为 “实参”。
2.5、函数返回值
所谓“返回值”,就是程序中函数完成一件事情后,最后给调用者的结果。
2.6、带有返回值的函数
想要在函数中把结果返回给调用者,需要在函数中使用 return
。
如下示例:
1 | def add2num(a, b): c = a+b return c |
或者
1 | def add2num(a, b): return a+b |
也可以利用元组,返回多个值:
1 | >>> def divid(a, b): ... shang = a//b ... yushu = a%b ... return shang, yushu ... >>> sh, yu = divid(5, 2) >>> lb = divid(5, 2) >>> sh 2 >>> yu 1 >>> lb (2,1) |
2.7、保存函数的返回值
在本小节刚开始的时候,说过的“买烟”的例子中,最后儿子给你烟时,你一定是从儿子手中接过来 对么,程序也是如此,如果一个函数返回了一个数据,那么想要用这个数据,那么就需要保存。
保存函数的返回值示例如下:
1 | #定义函数 def add2num(a, b): return a+b #调用函数,顺便保存函数的返回值 result = add2num(100,98) #因为result已经保存了add2num的返回值,所以接下来就可以使用了 print(result) |
3、四种函数的类型
函数根据有没有参数,有没有返回值,可以相互组合,一共有4种:
- 无参数,无返回值
- 无参数,有返回值
- 有参数,无返回值
- 有参数,有返回值
3.1、无参数、无返回值
此类函数,不能接收参数,也没有返回值,一般情况下,打印提示灯类似的功能,使用这类的函数。
1 | def printMenu(): print('--------------------------') print(' xx涮涮锅 点菜系统') print('') print(' 1. 羊肉涮涮锅') print(' 2. 牛肉涮涮锅') print(' 3. 猪肉涮涮锅') print('--------------------------') |
结果:
3.2、无参数、有返回值
此类函数,不能接收参数,但是可以返回某个数据,一般情况下,像采集数据,用此类函数。
1 | # 获取温度 def getTemperature(): #这里是获取温度的一些处理过程 #为了简单起见,先模拟返回一个数据 return 24 temperature = getTemperature() print('当前的温度为:%d'%temperature) |
3.3、有参数、无返回值
此类函数,能接收参数,但不可以返回数据,一般情况下,对某些变量设置数据而不需结果时,用此类函数。
3.4、有参数、有返回值
此类函数,不仅能接收参数,还可以返回某个数据,一般情况下,像数据处理并需要结果的应用,用此类函数。
1 | # 计算1~num的累积和 def calculateNum(num): result = 0 i = 1 while i<=num: result = result + i i+=1 return result result = calculateNum(100) print('1~100的累积和为:%d'%result) |
3.5、小总结
- 函数根据有没有参数,有没有返回值可以相互组合
- 定义函数时,是根据实际的功能需求来设计的,所以不同开发人员编写的函数类型各不相同
4、函数的嵌套调用
4.1、概念
1 | def testB(): print('---- testB start----') print('这里是testB函数执行的代码...(省略)...') print('---- testB end----') def testA(): print('---- testA start----') testB() print('---- testA end----') testA() |
结果:
1 | ---- testA start---- ---- testB start---- 这里是testB函数执行的代码...(省略)... ---- testB end---- ---- testA end---- |
4.2、小总结
- 一个函数里面又调用了另外一个函数,这就是所谓的函数嵌套调用。
- 如果函数A中,调用了另外一个函数B,那么先把函数B中的任务都执行完毕之后才会回到上次函数A执行的位置。
5、变量
5.1、局部变量
如下图所示:
- 局部变量,就是在函数内部定义的变量
- 不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响
- 局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储,这就是它的作用
示例:
1 | def test1(): print(a) def test2(): print(a) # 调用函数 test1() test2() |
5.2、全局变量
如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量
示例:
1 | # 定义全局变量 a = 100 def test1(): print(a) def test2(): print(a) # 调用函数 test1() test2() |
运行结果:
1 | 100 100 |
5.4、变量重名
看如下代码:
既然全局变量能够在所有的函数中使用,那么可否进行修改呢?
示例:
5.5、可变类型的全局变量
1 | >>> a = 1 >>> def f(): ... a += 1 ... print(a) ... >>> f() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in f UnboundLocalError: local variable 'a' referenced before assignment >>> >>> >>> li = [1,] >>> def f2(): ... li.append(1) ... print(li) ... >>> f2() [1, 1] >>> li [1, 1] |
5.6、总结
- 在函数外边定义的变量叫做
全局变量
- 全局变量能够在所有的函数中进行访问
- 如果在函数中修改全局变量,那么就需要使用
global
进行声明,否则出错 - 如果全局变量的名字和局部变量的名字相同,那么调用的是局部变量。
- 在函数中不使用
global
声明全局变量时不能修改全局变量的本质是不能修改全局变量的指向,即不能将全局变量指向新的数据。 - 对于不可变类型的全局变量来说,因其指向的数据不能修改,所以不使用
global
时无法修改全局变量。 - 对于可变类型的全局变量来说,因其指向的数据可以修改,所以不使用
global
时也可修改全局变量。
6、函数的参数
6.1、默认参数
调用函数时,默认参数的值如果没有传入,则被认为是默认值。下例会打印默认的age,如果age没有被传入:
1 | def printinfo( name, age = 35 ): # 打印任何传入的字符串 print("Name: ", name) print("Age ", age) # 调用printinfo函数 printinfo(name="9527" ) printinfo( age=9,name="9527" ) |
以上实例输出结果:
1 | Name: 9527 Age 35 Name: 9527 Age 9 |
注意:带有默认值的参数一定要位于参数列表的最后面(可设置多个带默认值的参数)。
1 | >>> def printinfo(name, age=35, sex): ... print name ... File "<stdin>", line 1 SyntaxError: non-default argument follows default argument |
6.2、不定长参数
有时可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,声明时不会命名。
基本语法如下:
1 | def functionname([formal_args,] *args, **kwargs): "函数_文档字符串" function_suite return [expression] |
加了星号(*)的变量args会存放所有未命名的变量参数,args为元组;而加**的变量kwargs会存放命名参数,即形如key=value的参数, kwargs为字典。
1 | >>> def fun(a, b, *args, **kwargs): ... """可变参数演示示例""" ... print("a =", a) ... print("b =", b) ... print("args =", args) ... print("kwargs: ") ... for key, value in kwargs.items(): ... print(key, "=", value) ... >>> fun(1, 2, 3, 4, 5, m=6, n=7, p=8) # 注意传递的参数对应 a = 1 b = 2 args = (3, 4, 5) kwargs: p = 8 m = 6 n = 7 >>> >>> >>> >>> c = (3, 4, 5) >>> d = {"m":6, "n":7, "p":8} >>> fun(1, 2, *c, **d) # 注意元组与字典的传参方式 a = 1 b = 2 args = (3, 4, 5) kwargs: p = 8 m = 6 n = 7 >>> >>> >>> >>> fun(1, 2, c, d) # 注意不加星号与上面的区别 a = 1 b = 2 args = ((3, 4, 5), {'p': 8, 'm': 6, 'n': 7}) kwargs: >>> >>> |
6.3、引用传参
- 可变类型与不可变类型的变量分别作为函数参数时,会有什么不同吗?
- Python有没有类似C语言中的指针传参呢?
1 | >>> def selfAdd(a): ... """自增""" ... a += a ... >>> a_int = 1 >>> a_int 1 >>> selfAdd(a_int) >>> a_int 1 >>> a_list = [1, 2] >>> a_list [1, 2] >>> selfAdd(a_list) >>> a_list [1, 2, 1, 2] |
Python中函数参数是引用传递(注意不是值传递)。对于不可变类型,因变量不能修改,所以运算不会影响到变量自身;而对于可变类型来说,函数体中的运算有可能会更改传入的参数变量。
1 | >>> def selfAdd(a): ... """自增""" ... a = a + a # 我们更改了函数体的这句话 ... >>> a_int = 1 >>> a_int 1 >>> selfAdd(a_int) >>> a_int 1 >>> a_list = [1, 2] >>> a_list [1, 2] >>> selfAdd(a_list) >>> a_list [1, 2] # 想一想为什么没有变呢? |
7、鸣谢
转载自:
Zeruns's Blog
Python 理论知识(四)函数和变量
评论