Python学习之路6☞函数,递归,内置函数 一python中的函数 二 为何使用函数 三 函数和过程 四 函数是第一类对象 五 函数参数 六 局部变量和全局变量 七 前向引用之'函数即变量' 八 嵌套函数和作用域 九 递归调用

函数是逻辑结构化和过程化的一种编程方法。

python中函数定义方法:
 
def test(x):
    "The function definitions"
    x+=1
    return x
     
def:定义函数的关键字
test:函数名
():内可定义形参
"":文档描述(非必要,但是强烈建议为你的函数添加描述信息)
x+=1:泛指代码块或程序处理逻辑
return:定义返回值


调用运行:可以带参数也可以不带
函数名()

二 为何使用函数

背景提要

现在老板让你写一个监控程序,监控服务器的系统状况,当cpu\memory\disk等指标的使用量超过阀值时即发邮件报警,你掏空了所有的知识量,写出了以下代码

 1 while True:
 2     if cpu利用率 > 90%:
 3         #发送邮件提醒
 4         连接邮箱服务器
 5         发送邮件
 6         关闭连接
 7      
 8     if 硬盘使用空间 > 90%:
 9         #发送邮件提醒
10         连接邮箱服务器
11         发送邮件
12         关闭连接
13      
14     if 内存占用 > 80%:
15         #发送邮件提醒
16         连接邮箱服务器
17         发送邮件
18         关闭连接

上面的代码实现了功能,你这个重复代码太多了,每次报警都要重写一段发邮件的代码,太low了,这样干存在2个问题:

  1. 代码重复过多,一个劲的copy and paste不符合高端程序员的气质
  2. 如果日后需要修改发邮件的这段代码,比如加入群发功能,那你就需要在所有用到这段代码的地方都修改一遍

其实很简单,只需要把重复的代码提取出来,放在一个公共的地方,起个名字,以后谁想用这段代码,就通过这个名字调用就行了,如下

 1 def 发送邮件(内容)
 2     #发送邮件提醒
 3     连接邮箱服务器
 4     发送邮件
 5     关闭连接
 6      
 7 while True:
 8      
 9     if cpu利用率 > 90%:
10         发送邮件('CPU报警')
11      
12     if 硬盘使用空间 > 90%:
13         发送邮件('硬盘报警')
14      
15     if 内存占用 > 80%:
16         发送邮件('内存报警')

总结使用函数的好处:

1.代码重用

2.保持一致性,易维护

3.可扩展性

三 函数和过程

过程定义:过程就是简单特殊没有返回值的函数

这么看来我们在讨论为何使用函数的的时候引入的函数,都没有返回值,没有返回值就是过程,没错,但是在python中有比较神奇的事情

 1 def test01():
 2     msg='hello The little green frog'
 3     print msg
 4  
 5 def test02():
 6     msg='hello WuDaLang'
 7     print msg
 8     return msg
 9  
10  
11 t1=test01()
12  
13 t2=test02()
14  
15  
16 print 'from test01 return is [%s]' %t1
17 print 'from test02 return is [%s]' %t2

总结:当一个函数/过程没有使用return显示的定义返回值时,python解释器会隐式的返回None,

所以在python中即便是过程也可以算作函数。

 1 def test01():
 2     pass
 3  
 4 def test02():
 5     return 0
 6  
 7 def test03():
 8     return 0,10,'hello',['alex','lb'],{'WuDaLang':'lb'}
 9  
10 t1=test01()
11 t2=test02()
12 t3=test03()
13  
14  
15 print 'from test01 return is [%s]: ' %type(t1),t1
16 print 'from test02 return is [%s]: ' %type(t2),t2
17 print 'from test03 return is [%s]: ' %type(t3),t3

总结:

   返回值数=0:返回None

   返回值数=1:返回object

   返回值数>1:返回tuple

四 函数是第一类对象

在python中所有的名字都没有储值功能

函数是第

1 def foo():
2     print("yyp")
3 f1=foo
4 f1()
5 # 输出结果:
6 yyp

可以当做参数

 1 def foo():
 2     print("tom")
 3 
 4 def func(msg):
 5     print(msg)
 6     msg()
 7 
 8 func(foo)
 9 输出结果:
10 <function foo at 0x00000000020D3E18>
11 tom

可以当做返回值

 1 def foo():
 2     print("tom")
 3 
 4 def func(msg):
 5     return msg
 6 
 7 f=func(foo)
 8 print(f)
 9 f()
10 输出结果:
11 <function foo at 0x0000000002423E18>
12 tom

可以当做容器类型的一个元素

1 def foo():
2     print("tom")
3 
4 func_dic={
5     'foo':foo
6 }
7 输出结果:
8 tom

一类对象指的是:函数可以被当做数据来处理被引用

五 函数参数

1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量

2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

Python学习之路6☞函数,递归,内置函数
一python中的函数
二 为何使用函数
三 函数和过程
四 函数是第一类对象
五 函数参数
六 局部变量和全局变量
七 前向引用之'函数即变量'
八 嵌套函数和作用域
九 递归调用

3.位置参数和关键字(标准调用:实参与形参位置一一对应;关键字调用:位置无需固定)

4.默认参数

5.参数组

六 局部变量和全局变量

在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。

全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
当全局变量与局部变量同名时:
在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。
 1 name='lhf'
 2 
 3 def change_name():
 4     print('我的名字',name)
 5 
 6 change_name()
 7 
 8 
 9 def change_name():
10     name='帅了一笔'
11     print('我的名字',name)
12 
13 change_name()
14 print(name)
15 
16 
17 
18 def change_name():
19     global name
20     name='帅了一笔'
21     print('我的名字',name)
22 
23 change_name()
24 print(name)

七 前向引用之'函数即变量'

 1 def action():
 2     print 'in the action'
 3     logger()
 4 action()
 5 报错NameError: global name 'logger' is not defined
 6 
 7 
 8 def logger():
 9     print 'in the logger'
10 def action():
11     print 'in the action'
12     logger()
13  
14 action()
15  
16 
17 def action():
18     print 'in the action'
19     logger()
20 def logger():
21     print 'in the logger'
22  
23 action()

八 嵌套函数和作用域

看上面的标题的意思是,函数还能套函数?of course

 1 name = "yyp"
 2  
 3 def change_name():
 4     name = "yyp2"
 5  
 6     def change_name2():
 7         name = "yyp3"
 8         print("第3层打印",name)
 9  
10     change_name2() #调用内层函数
11     print("第2层打印",name)
12  
13  
14 change_name()
15 print("最外层打印",name)

此时,在最外层调用change_name2()会出现什么效果?

没错, 出错了, 为什么呢?

作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变

 1 例一:
 2 name='yyp'
 3 
 4 def foo():
 5     name='sy'
 6     def bar():
 7         print(name)
 8     return bar
 9 
10 func=foo()
11 func()
12 
13 
14 例二:
15 name='yyp'
16 
17 def foo():
18     name='sy'
19     def bar():
20         name='tom'
21         def tt():
22             print(name)
23         return tt
24     return bar
25 
26 func=foo()
27 func()()

九 递归调用

 1 def calc(n):
 2     print(n)
 3     if int(n/2) ==0:
 4         return n
 5     return calc(int(n/2))
 6  
 7 calc(10)
 8  
 9 输出:
10 10
11 5
12 2
13 1
 1 #_*_coding:utf-8_*_
 2 __author__ = 'Linhaifeng'
 3 import time
 4 
 5 person_list=['alex','wupeiqi','yuanhao','linhaifeng']
 6 def ask_way(person_list):
 7     print('-'*60)
 8     if len(person_list) == 0:
 9         return '没人知道'
10     person=person_list.pop(0)
11     if person == 'linhaifeng':
12         return '%s说:我知道,老男孩就在沙河汇德商厦,下地铁就是' %person
13     print('hi 美男[%s],敢问路在何方' %person)
14     print('%s回答道:我不知道,但念你慧眼识猪,你等着,我帮你问问%s...' %(person,person_list))
15     time.sleep(3)
16     res=ask_way(person_list)
17     # print('%s问的结果是: %res' %(person,res))
18     return res
19 
20 
21 
22 res=ask_way(person_list)
23 
24 print(res)
递归问路

递归特性:

1. 必须有一个明确的结束条件

2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

链接:堆栈扫盲

 1 data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
 2  
 3  
 4 def binary_search(dataset,find_num):
 5     print(dataset)
 6  
 7     if len(dataset) >1:
 8         mid = int(len(dataset)/2)
 9         if dataset[mid] == find_num:  #find it
10             print("找到数字",dataset[mid])
11         elif dataset[mid] > find_num :# 找的数在mid左面
12             print("