首页 > 代码库 > Python学习之路6?函数,递归,内置函数
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个问题:
- 代码重复过多,一个劲的copy and paste不符合高端程序员的气质
- 如果日后需要修改发邮件的这段代码,比如加入群发功能,那你就需要在所有用到这段代码的地方都修改一遍
其实很简单,只需要把重复的代码提取出来,放在一个公共的地方,起个名字,以后谁想用这段代码,就通过这个名字调用就行了,如下
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.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
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 = http://www.mamicode.com/[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("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid]) 13 return binary_search(dataset[0:mid], find_num) 14 else:# 找的数在mid右面 15 print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid]) 16 return binary_search(dataset[mid+1:],find_num) 17 else: 18 if dataset[0] == find_num: #find it 19 print("找到数字啦",dataset[0]) 20 else: 21 print("没的分了,要找的数字[%s]不在列表里" % find_num) 22 23 24 binary_search(data,66)
十 匿名函数
匿名函数就是不需要显式的指定函数
1 #这段代码 2 def calc(n): 3 return n**n 4 print(calc(10)) 5 6 #换成匿名函数 7 calc = lambda n:n**n 8 print(calc(10))
匿名函数主要是和其它函数搭配使用的呢,如下
1 l=[3,2,100,999,213,1111,31121,333] 2 print(max(l)) 3 4 dic={‘k1‘:10,‘k2‘:100,‘k3‘:30} 5 6 7 print(max(dic)) 8 print(dic[max(dic,key=lambda k:dic[k])])
1 res = map(lambda x:x**2,[1,5,7,4,8]) 2 for i in res: 3 print(i) 4 5 输出 6 1 7 25 8 49 9 16 10 64
十一 函数式编程
函数式编程:
http://egon09.blog.51cto.com/9161406/1842475
11 高阶函数
满足俩个特性任意一个即为高阶函数
1.函数的传入参数是一个函数名
2.函数的返回值是一个函数名
1 array=[1,3,4,71,2] 2 3 ret=[] 4 for i in array: 5 ret.append(i**2) 6 print(ret) 7 8 #如果我们有一万个列表,那么你只能把上面的逻辑定义成函数 9 def map_test(array): 10 ret=[] 11 for i in array: 12 ret.append(i**2) 13 return ret 14 15 print(map_test(array)) 16 17 #如果我们的需求变了,不是把列表中每个元素都平方,还有加1,减一,那么可以这样 18 def add_num(x): 19 return x+1 20 def map_test(func,array): 21 ret=[] 22 for i in array: 23 ret.append(func(i)) 24 return ret 25 26 print(map_test(add_num,array)) 27 #可以使用匿名函数 28 print(map_test(lambda x:x-1,array)) 29 30 31 #上面就是map函数的功能,map得到的结果是可迭代对象 32 print(map(lambda x:x-1,range(5)))
from functools import reduce #合并,得一个合并的结果 array_test=[1,2,3,4,5,6,7] array=range(100) #报错啊,res没有指定初始值 def reduce_test(func,array): l=list(array) for i in l: res=func(res,i) return res # print(reduce_test(lambda x,y:x+y,array)) #可以从列表左边弹出第一个值 def reduce_test(func,array): l=list(array) res=l.pop(0) for i in l: res=func(res,i) return res print(reduce_test(lambda x,y:x+y,array)) #我们应该支持用户自己传入初始值 def reduce_test(func,array,init=None): l=list(array) if init is None: res=l.pop(0) else: res=init for i in l: res=func(res,i) return res print(reduce_test(lambda x,y:x+y,array)) print(reduce_test(lambda x,y:x+y,array,50))
1 #电影院聚集了一群看电影bb的傻逼,让我们找出他们 2 movie_people=[‘alex‘,‘wupeiqi‘,‘yuanhao‘,‘sb_alex‘,‘sb_wupeiqi‘,‘sb_yuanhao‘] 3 4 def tell_sb(x): 5 return x.startswith(‘sb‘) 6 7 8 def filter_test(func,array): 9 ret=[] 10 for i in array: 11 if func(i): 12 ret.append(i) 13 return ret 14 15 print(filter_test(tell_sb,movie_people)) 16 17 18 #函数filter,返回可迭代对象 19 print(filter(lambda x:x.startswith(‘sb‘),movie_people))
1 #当然了,map,filter,reduce,可以处理所有数据类型 2 3 name_dic=[ 4 {‘name‘:‘alex‘,‘age‘:1000}, 5 {‘name‘:‘wupeiqi‘,‘age‘:10000}, 6 {‘name‘:‘yuanhao‘,‘age‘:9000}, 7 {‘name‘:‘linhaifeng‘,‘age‘:18}, 8 ] 9 #利用filter过滤掉千年王八,万年龟,还有一个九千岁 10 def func(x): 11 age_list=[1000,10000,9000] 12 return x[‘age‘] not in age_list 13 14 15 res=filter(func,name_dic) 16 for i in res: 17 print(i) 18 19 res=filter(lambda x:x[‘age‘] == 18,name_dic) 20 for i in res: 21 print(i) 22 23 24 #reduce用来计算1到100的和 25 from functools import reduce 26 print(reduce(lambda x,y:x+y,range(100),100)) 27 print(reduce(lambda x,y:x+y,range(1,101))) 28 29 #用map来处理字符串列表啊,把列表中所有人都变成sb,比方alex_sb 30 name=[‘alex‘,‘wupeiqi‘,‘yuanhao‘] 31 32 res=map(lambda x:x+‘_sb‘,name) 33 for i in res: 34 print(i)
十二 内置函数
1 字典的运算:最小值,最大值,排序 2 salaries={ 3 ‘egon‘:3000, 4 ‘alex‘:100000000, 5 ‘wupeiqi‘:10000, 6 ‘yuanhao‘:2000 7 } 8 9 迭代字典,取得是key,因而比较的是key的最大和最小值 10 >>> max(salaries) 11 ‘yuanhao‘ 12 >>> min(salaries) 13 ‘alex‘ 14 15 可以取values,来比较 16 >>> max(salaries.values()) 17 >>> min(salaries.values()) 18 但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键 19 >>> max(salaries,key=lambda k:salary[k]) 20 ‘alex‘ 21 >>> min(salaries,key=lambda k:salary[k]) 22 ‘yuanhao‘ 23 24 25 26 也可以通过zip的方式实现 27 salaries_and_names=zip(salaries.values(),salaries.keys()) 28 29 先比较值,值相同则比较键 30 >>> max(salaries_and_names) 31 (100000000, ‘alex‘) 32 33 34 salaries_and_names是迭代器,因而只能访问一次 35 >>> min(salaries_and_names) 36 Traceback (most recent call last): 37 File "<stdin>", line 1, in <module> 38 ValueError: min() arg is an empty sequence 39 40 41 42 sorted(iterable,key=None,reverse=False)
Python学习之路6?函数,递归,内置函数