函数
函数介绍
什么是函数
请看如下代码:
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 " 不见满街漂亮妹,哪个归得程序员?"
运行后的现象:
佛祖镇楼
想一想:
如果一个程序在不同的地方需要输出“佛祖镇楼”,程序应该怎样设计?
if 条件1:
输出‘佛祖镇楼’
...(省略)...
if 条件2:
输出‘佛祖镇楼’
...(省略)...
如果需要输出多次,是否意味着要编写这块代码多次呢?
小结:
如果在开发程序时,需要某块代码多次,但是为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数
函数的定义与调用
<1>定义函数
定义函数的格式如下:
def 函数名():
代码
# 定义一个函数,能够完成打印信息的功能
def printInfo():
print '------------------------------------'
print ' 人生苦短,我用Python'
print '------------------------------------'
<2>调用函数
定义了函数之后,就相当于有了一个具有某些功能的代码,想要让这些代码能够执行,需要调用它
调用函数很简单的,通过 函数名() 即可完成调用
demo:
# 定义完函数后,函数是不会自动执行的,需要调用它才可以
printInfo()
函数的文档说明
def test(a,b):
"用来完成对2个数求和"
print("%d"%(a+b))
test(11,22)
33
当同事或者自己需要查看 函数(test)的说明时:
(也可以按住键盘CTRL 然后鼠标点击目标函数)
help(test) #能够看到test函数的相关说明
Help on function test in module __main__:
test(a, b)
用来完成对2个数求和
函数的参数
思考一个问题,如下:
现在需要定义一个函数,这个函数能够完成2个数的加法运算,并且把结果打印出来,该怎样设计?下面的代码可以吗?有什么缺陷吗?
def add2num():
a = 11
b = 22
c = a+b
print c
没错,在我们想要调用这个函数的时候,发现根本无从下手,不知道怎么使用这个函数。
为了让一个函数更通用,即想让它计算哪两个数的和,就让它计算哪两个数的和,在定义函数的时候可以让函数接收数据,就解决了这个问题,这就是 函数的参数
<1> 定义带有参数的函数
示例如下:
def add2num(a, b): #a,b即这个函数的参数
c = a+b
print c
<2> 调用带有参数的函数
以调用上面的add2num(a, b)函数为例:
def add2num(a, b):
c = a+b
print c
add2num(11, 22) #调用带有参数的函数时,需要在小括号中,传递数据
调用带有参数函数的运行过程:
<3> 调用函数时 参数的顺序
#定义函数==============
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
小结
定义时小括号中的参数,用来接收参数用的,称为 “形参”
调用时小括号中的参数,用来传递给函数用的,称为 “实参”
函数返回值(一)
<1>“返回值”介绍
现实生活中的场景:
去自动售货机买饮料,自动售货只卖3种价格的饮料,投币口只支持5元、10元、20元这3种规格的纸币。
在这个例子中:
函数:售货机
形参:售货机投币口
实参:3种不同规格的纸币
返回值:对应价格的饮料
你往售货机里放不同面额的纸币,售货机的取货口会落下相应规格的饮料,这就完成了一个完整的函数调用。
开发中的场景:
定义了一个函数,完成了获取室内温度,想一想是不是应该把这个结果给调用者,只有调用者拥有了这个返回值,才能够根据当前的温度做适当的调整
综上所述:
- 所谓“返回值”,就是程序中函数完成一件事情后,最后给调用者的结果
<2>带有返回值的函数
想要在函数中把结果返回给调用者,需要在函数中使用return
如下示例:
def add2num(a, b):
c = a+b
return c
或者
def add2num(a, b):
return a+b
<3>保存函数的返回值
如果一个函数返回了一个数据,那么想要用这个数据,那么就需要保存
保存函数的返回值示例如下:
#定义函数
def add2num(a, b):
return a+b
#调用函数,顺便保存函数的返回值
result = add2num(100,98)
#因为result已经保存了add2num的返回值,所以接下来就可以使用了
print result
结果:
198
4种函数的类型
函数根据有没有参数,有没有返回值,可以相互组合,一共有4种
- 无参数,无返回值
- 无参数,有返回值
- 有参数,无返回值
- 有参数,有返回值
<1>无参数,无返回值的函数
此类函数,不能接收参数,也没有返回值,一般情况下,打印提示灯类似的功能,使用这类的函数
def printMenu():
print('--------------------------')
print('打印菜单栏')
print('--------------------------')
<2>无参数,有返回值的函数
此类函数,不能接收参数,但是可以返回某个数据,一般情况下,像采集数据,用此类函数
# 获取温度
def getTemperature():
#这里是获取温度的一些处理过程
#为了简单起见,先模拟返回一个数据
return 24
temperature = getTemperature()
print('当前的温度为:%d'%temperature)
结果:
当前的温度为: 24
<3>有参数,无返回值的函数
此类函数,能接收参数,但不可以返回数据,一般情况下,对某些变量设置数据而不需结果时,用此类函数
<4>有参数,有返回值的函数
此类函数,不仅能接收参数,还可以返回某个数据,一般情况下,像数据处理并需要结果的应用,用此类函数
# 计算1~num的累加和
def sum1to100(a):
if a==1: #出栈条件一定不能忘
return 1
else:
a=a
return a+sum1to100(a-1)
print('1~100的累积和为',sum1to100(100))
结果:
1~100的累积和为: 5050
<5>小结
函数根据有没有参数,有没有返回值可以相互组合
定义函数时,是根据实际的功能需求来设计的,所以不同开发人员编写的函数类型各不相同
函数的嵌套调用
def testB():
print('---- testB start----')
print('这里是testB函数执行的代码...(省略)...')
print('---- testB end----')
def testA():
print('---- testA start----')
testB()
print('---- testA end----')
testA()
结果:
---- testA start----
---- testB start----
这里是testB函数执行的代码...(省略)...
---- testB end----
---- testA end----
小结:
- 一个函数里面又调用了另外一个函数,这就是所谓的函数嵌套调用
- 如果函数A中,调用了另外一个函数B,那么先把函数B中的任务都执行完毕之后才会回到上次 函数A执行的位置
函数的简单应用:打印图形和数学计算
目标
- 感受函数的嵌套调用
- 感受程序设计的思路,复杂问题分解为简单问题
思考&实现1
- 写一个函数打印一条横线
- 打印自定义行数的横线
参考代码1
# 打印一条横线
def printLine():
print('-'*10)
printLine()
—————华丽的分割线—————
# 打印自定义数量条横线
def printLines(num):
for i in range(num):
print('=' * 10)
printNumLine(3)
思考&实现2
- 写一个函数求三个数的和
- 写一个函数求三个数的平均值
参考代码2
# 求3个数的和
def sum3num(a,b,c):
return a+b+c
print(sum3num(1,2,3)) 的后面可以是数值,也可是一个表达式
—————华丽的分割线—————
# 完成对3个数求平均值
def ave3num(a,b,c):
print((a+b+c)/3)
return int((a+b+c)/3) #int位置按照需求选择数据类型
print(ave3num(1,2,3))
LEGB原则(很重要)
LEGB是由4个英文单词缩写而来:Local-Enclosed-Global-Built in
Local #函数或类名的内部
Enclosed #嵌套函数,(一个函数包裹另外一个函数,闭包)
Global #指模块中的全局变量
Built in #Python为自己保留的特殊名称
如果在某个name映射在局部(local)命名空间中没有找到,接下来就会在闭包作用域中(Enclosed)中寻找,如果闭包作用域没有找到,就会在全局命名(Global)空间寻找,最后会在内建(Built in)命名空间寻找,如果一个名称在所有的命名空间都没有找到,就会报Nameerro错误
以下为LEGB寻找规则示例:
# LEGB
a=1
b=2
c=3
d=4
def waibu():
a=5
b=6
def neibu():
c=6
print(a)#enclose 5
print(b)#enclose 6
print(c)#local 6
print(d)#gloabl 4
print(max)#built-in
neibu()#函数内部调用
waibu()
函数使用注意事项
1. 自定义函数
<1>无参数、无返回值
def 函数名():
语句
<2>无参数、有返回值
def 函数名():
语句
return 需要返回的数值
注意:
- 一个函数到底有没有返回值,就看有没有return,因为只有return才可以返回数据
- 在开发中往往根据需求来设计函数需不需要返回值
- 函数中,可以有多个return语句,但是只要执行到一个return语句,那么就意味着这个函数的调用完成
<3>有参数、无返回值
def 函数名(形参列表):
语句
注意:
- 在调用函数时,如果需要把一些数据一起传递过去,被调用函数就需要用参数来接收
- 参数列表中变量的个数根据实际传递的数据的多少来确定
<4>有参数、有返回值
def 函数名(形参列表):
语句
return 需要返回的数值
<5>函数名不能重复
2. 调用函数
<1>调用的方式为:
函数名([实参列表])
<2>调用时,到底写不写 实参
- 如果调用的函数 在定义时有形参,那么在调用的时候就应该传递参数
<3>调用时,实参的个数和先后顺序应该和定义函数中要求的一致
<4>如果调用的函数有返回值,那么就可以用一个变量来进行保存这个值
3. 作用域
<1>在一个函数中定义的变量,只能在本函数中用(局部变量)
<2>在函数外定义的变量,可以在所有的函数中使用(全局变量)
缺省参数*args **kwargs
调用函数时,缺省参数的值如果没有传入,则被认为是默认值。下例会打印默认的age,如果age没有被传入:
def printinfo( name, age = 35 ):
# 打印任何传入的字符串
print "Name: ", name
print "Age ", age
# 调用printinfo函数
printinfo(name="miki" )
printinfo( age=9,name="miki" )
以上实例输出结果:
Name: miki
Age 35
Name: miki
Age 9
注意:带有默认值的参数一定要位于参数列表的最后面,否则程序报异常。
>>> def printinfo(name, age=35, sex):
... print name
...
File "<stdin>", line 1
SyntaxError: non-default argument follows default argument
2.不定长参数
2.不定长参数
有时可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,声明时不会命名。
基本语法如下:
def functionname([formal_args,] *args, **kwargs):
"函数_文档字符串"
function_suite
return [expression]
加了星号(*)的变量args会存放所有未命名的变量参数,args为元组;而加**的变量kwargs会存放命名参数,即形如key=value的参数, kwargs为字典。
>>> 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:
>>>
>>>
递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
简单来说,就是一个函数调用了他本身。
举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示,可以看出:
fact(n) = n! = 1 x 2 x 3 x … x (n-1) x n = (n-1)! x n = fact(n-1) x n
所以,fact(n)可以表示为n x fact(n-1),只有n=1时需要特殊处理。
于是,fact(n)用递归的方式写出来就是:
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
上面就是一个递归函数。可以试试:
>>> fact(1)
1
>>> fact(5)
120
>>> fact(100)
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
如果我们计算fact(5),可以根据函数定义看到计算过程如下:
===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120
递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
匿名函数
匿名函数
用lambda关键词能创建小型匿名函数。这种函数得名于省略了用def声明函数的标准步骤。
lambda函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,.....argn]]:expression
如下实例:
sum = lambda arg1, arg2: arg1 + arg2
#调用sum函数
print "Value of total : ", sum( 10, 20 )
print "Value of total : ", sum( 20, 20 )
以上实例输出结果:
Value of total : 30
Value of total : 40
Lambda函数能接收任何数量的参数但只能返回一个表达式的值
匿名函数不能直接调用print,因为lambda需要一个表达式
应用场合
函数作为参数传递
- 自己定义函数
def fun(a, b, opt):
print "a =", a
print "b =", b
print "result =", opt(a, b)
fun(1, 2, lambda x,y:x+y)
a = 1
b = 2
result = 3
- 作为内置函数的参数
示例
stus = [
{"name":"zhangsan", "age":18},
{"name":"lisi", "age":19},
{"name":"wangwu", "age":17}
]
按name排序:
>>> stus.sort(key = lambda x:x['name'])
>>> stus
[{'age': 19, 'name': 'lisi'}, {'age': 17, 'name': 'wangwu'}, {'age': 18, 'name': 'zhangsan'}]
按age排序:
>>> stus.sort(key = lambda x:x['age'])
>>> stus
[{'age': 17, 'name': 'wangwu'}, {'age': 18, 'name': 'zhangsan'}, {'age': 19, 'name': 'lisi'}]