函数的基本概述
在学习函数之前,一直遵循:面向过程编程,即:根据业务逻辑从上到下实现功能,可以思考一下如果有某个功能的代码是在多个地方使用的是否可以只写一次?此时的代码该如何定义。先观察以下的案例:
while True:
if cpu利用率 > 90%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接
if 硬盘使用空间 > 90%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接
if 内存占用 > 80%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接
以上代码中每个if条件语句下内容可以被提取出来公用 例:
def 发送邮件(内容)
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接
while True:
if cpu利用率 > 90%:
发送邮件('CPU报警')
if 硬盘使用空间 > 90%:
发送邮件('硬盘报警')
if 内存占用 > 80%:
发送邮件('内存报警')
对于上述的两种实现方式,第二次必然比第一次的重用性和可读性要好,可以减少大量的代码量,减少开发时间,一处定义,多处调用,其实这就是函数式编程
函数式编程的概念:
开发程序时,需要某块代码多次使用,但是为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数
函数的定义和调用
<1>定义函数
定义函数的格式如下:
def 函数名():
代码
demo:
# 定义一个函数,能够完成打印信息的功能
def printInfo():
print '------------------------------------'
print ' 人生苦短,我用Python'
print '------------------------------------'
函数的定义主要有如下要点:
• def:表示函数的关键字 • 函数名:函数的名称,调用时根据函数名调用函数
• 函数体:函数中进行一系列的逻辑计算或是该函数的功能内容。
• 参数:为函数体提供数据
• 返回值:当函数执行完毕后,可以给调用者返回数据。
<2>调用函数
定义了函数之后,就相当于有了一个具有某些功能的代码,想要让这些代码能够执行,需要调用它(注意在定义函数时里面的内容不会执行)
调用函数很简单的,通过 函数名() 即可完成调用
demo:
# 定义完函数后,函数是不会自动执行的,需要调用它才可以
printInfo()
<3>函数的文档说明
例:
>>> def test(a,b):
... "用来完成对2个数求和"
... print("%d"%(a+b))
...
>>>
>>> test(11,22)
33
执行,以下代码
>>> help(test)
能够看到test函数的相关说明
==============================================
Help on function test in module __main__:
test(a, b)
用来完成对2个数求和
(END)
=============================================
函数的参数-返回值
<1> 定义带有参数的函数
示例如下:
def addnum(a, b):
c = a+b
print c
<2> 调用带有参数的函数
以调用上面的add2num(a, b)函数为例:
def addnum(a, b):
c = a+b
print c
add2num(11, 22) #调用带有参数的函数时,需要在小括号中,传递数据
小总结:
• 定义时小括号中的参数,用来接收参数用的,称为 “形参”
• 调用时小括号中的参数,用来传递给函数用的,称为 “实参”
ps:后面会有单独一篇详解函数参数的博客
<3> 带有返回值的函数
如下示例:
def add2num(a, b):
c = a+b
return c
保存函数的返回值示例如下:
#定义函数
def add2num(a, b):
return a+b
#调用函数,顺便保存函数的返回值
result = add2num(100,98)
#因为result已经保存了add2num的返回值,所以接下来就可以使用了
print result
结果:
198
在python中我们可以返回多个值
>>> def divid(a, b):
... shang = a//b
... yushu = a%b
... return shang, yushu
...
>>> sh, yu = divid(5, 2)
>>> sh
5
>>> yu
1
本质是利用了元组
函数根据有没有参数,有没有返回值,可以相互组合,一共有4种
• 无参数,无返回值
• 无参数,无返回值
• 有参数,无返回值
• 有参数,有返回值
<1>无参数,无返回值的函数
此类函数,不能接收参数,也没有返回值,一般情况下,打印提示灯类似的功能,使用这类的函数
<2>无参数,有返回值的函数
此类函数,不能接收参数,但是可以返回某个数据,一般情况下,像采集数据,用此类函数
<3>有参数,无返回值的函数
此类函数,能接收参数,但不可以返回数据,一般情况下,对某些变量设置数据而不需结果时,用此类函数
<4>有参数,有返回值的函数
此类函数,不仅能接收参数,还可以返回某个数据,一般情况下,像数据处理并需要结果的应用,用此类函数
小总结
• 函数根据有没有参数,有没有返回值可以相互组合
• 定义函数时,是根据实际的功能需求来设计的,所以不同开发人员编写的函数类型各不相同
• 一个函数到底有没有返回值,就看有没有return,因为只有return才可以返回数据
• 在开发中往往根据需求来设计函数需不需要返回值
• 函数中,可以有多个return语句,但是只要执行到一个return语句,那么就意味着这个函数的调用完成
• 一个程序当中函数的名字尽量不要重复,当函数名字重复时后面的会把前面的覆盖掉(注意:也不要与变量名重复同样会被覆盖)
函数的嵌套
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. 写一个函数求三个数的和
2. 写一个函数求三个数的平均值
# 求3个数的和
def sum3Number(a,b,c):
return a+b+c # return 的后面可以是数值,也可是一个表达式
# 完成对3个数求平均值
def average3Number(a,b,c):
# 因为sum3Number函数已经完成了3个数的就和,所以只需调用即可
# 即把接收到的3个数,当做实参传递即可
sumResult = sum3Number(a,b,c)
aveResult = sumResult/3.0
return aveResult
# 调用函数,完成对3个数求平均值
result = average3Number(11,2,55)
print("average is %d"%result)
函数的局部变量、全局变量
局部变量
示例:
In [8]: def text1():
...: a = 200
...: print("text1----%d" %a)
...: print("修改后")
...: a = 300
...: print("text1----%d" %a)
...:
In [9]: def text2():
...: a = 400
...: print("text2-----%d" %a)
...:
In [10]: text1()
text1----200
修改后
text1----300
In [11]: text2()
text2-----400
总结
• 局部变量,就是在函数内部定义的变量
• 不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响
• 局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储,这就是它的作用
全局变量
概念:如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量
示例:
# 定义全局变量
In [12]: a = 250
In [13]: def text1():
...: print("----text1----%d" %a)
...:
In [14]: def text2():
...: print("----text2----%d" %a)
...:
In [15]: text1()
----text1----250
In [16]: text2()
----text2----250
当局部变量和全局变量重名的时候:
In [23]: a = 250 # 全局变量
In [24]: def text1():
...: # 局部变量
...: a = 521
...: print("----text1----%d" %a)
...: # 局部变量
...: a = 666
...: print("----text1----%d" %a)
...:
In [25]: def text2():
...: print("----text2----%d" %a)
...:
In [26]: text1()
----text1----521
----text1----666
In [27]: text2()
----text2----250
In [28]:
总结:
• 在函数外边定义的变量叫做全局变量
• 全局变量能够在所有的函数中进行访问
• 如果全局变量的名字和局部变量的名字相同,那么使用的是局部变量的,小技巧强龙不压地头蛇
在函数内部修改全局变量:
In [31]: a = 250
In [32]: def text1():
...: a = 520
...: print("----text1----%d" %a)
In [33]:
In [33]: def text2():
...: global a
...: a = 666
...: print("----text2----%d" %a)
...:
In [34]: # 没有调用任何函数
In [35]: print(a)
250
In [36]: # 调用text1
In [37]: text1()
----text1----520
In [38]: # 再次打印---->
In [39]: print(a)
250
In [40]: # 发现值并没有修改
In [41]: # 调用text2
In [42]: text2()
----text2----666
In [43]: # 再次打印a
In [44]: print(a)
666
In [45]: # 值已修改
总结:
• 如果在函数中修改全局变量,那么就需要使用global进行声明,否则相当于在(在没有传参数的情况)在函数内部重新定义了一个相同变量的对象
对于 --可变类型的全局变量-和-不可变类型的全局变量-在函数内部修改的区别
ps:后面会有博客详细说明可变类型与不可变类型的概念
示例:------->不可变类型:
In [46]: a = 6
In [47]: def demo():
...: a += 1
...: print(a)
...:
In [48]: demo()
错误信息:
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-48-00cf94af4371> in <module>()
----> 1 demo()
<ipython-input-47-6e1d5ad81f64> in demo()
1 def demo():
----> 2 a += 1
3 print(a)
4
UnboundLocalError: local variable 'a' referenced before assignment
--------------------------------------------------------------------------
注:显然是不可以修改
------->可变类型:
In [49]: a = [1,]
In [50]:
In [50]: def demo():
...: a.append(2)
...: print(a)
...:
In [51]: demo()
[1, 2]
In [52]: a
Out[52]: [1, 2]
当调用函数时,在执行函数时在函数内部修改了列表的值--同时外部打印时也发生了变化。
总结:
○ 如果在函数中修改全局变量,那么就需要使用global进行声明,否则出错
○ 在函数中不使用global声明全局变量时不能修改全局变量的本质是不能修改全局变量的指向,即不能将全局变量指向新的数据。
○ 对于不可变类型的全局变量来说,因其指向的数据不能修改,所以不使用global时无法修改全局变量。
○ 对于可变类型的全局变量来说,因其指向的数据可以修改,所以不使用global时也可修改全局变量。