python中的函数
---恢复内容开始---
一 数学定义的函数与python中的函数
初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因变量,y是x的函数。自变量x的取值范围叫做这个函数的定义域
例如y=2*x
python中函数定义:函数是逻辑结构化和过程化的一种编程方法。
python中函数定义方法: 2 3 def test(x): 4 "The function definitions" 5 x+=1 6 return x 7 8 def:定义函数的关键字 9 test:函数名 10 ():内可定义形参 11 "":文档描述(非必要,但是强烈建议为你的函数添加描述信息) 12 x+=1:泛指代码块或程序处理逻辑 13 return:定义返回值 调用运行:可以带参数也可以不带 函数名()
补充:
1、编程语言中的函数与数学意义是截然不同的概念,编程语言中的函数是通过一个函数名封装好一串,用来完成某一特定功能的逻辑,数学定义的函数就是一个等式,等式在传入因变量值x不同会得到一个结果y,这一点与编程语言中类似(也是传入一个参数,得到一个返回值),不同的是数学意义的函数,传入值相同,得到的结果必然相同且没有任何变量的修改(不修改状态),而编程语言中的函数传入的参数相同返回值可不一定相同且,可以修改其他的全局变量值(因为一个函数a的执行可能依赖于另外一个函数b的结果,b可能得到不同结果,那即便是你给a传入相同的参数,那么a得到结果肯定也不同)
2、函数式编程就是:先定义一个数学函数,然后按照这个数学模型用编程语言去实现它,至于具体如何实现和怎么做的好处,且看后续的函数式编程
二 为何使用函数
背景提要
现在老板让你写一个监控程序,监控服务器的系统状况,当cpu\memory\disk等指标的使用量超过阀值时即发邮件报警,你掏空了所有的知识量,写出了以下代码
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 关闭连接
三 函数和过程
过程定义:过程就是简单特殊没有返回值的函数
这么看来我们在讨论为何使用函数的的时候引入的函数,都没有返回值,没有返回值就是过程,没错,但是在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中即便是过程也可以算作函数。
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
四 函数参数
1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
3.位置参数和关键字(标准调用:实参与形参位置一一对应;关键字调用:位置无需固定)
4.默认参数
5.参数组
五 局部变量和全局变量
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)
六 前向引用之'函数即变量'
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 = "Alex" 2 3 def change_name(): 4 name = "Alex2" 5 6 def change_name2(): 7 name = "Alex3" 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='alex' 3 4 def foo(): 5 name='lhf' 6 def bar(): 7 print(name) 8 return bar 9 10 func=foo() 11 func() 12 13 14 例二: 15 name='alex' 16 17 def foo(): 18 name='lhf' 19 def bar(): 20 name='wupeiqi' 21 def tt(): 22 print(name) 23 return tt 24 return bar 25 26 func=foo() 27 func()()
八 递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
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
#_*_coding:utf-8_*_ __author__ = 'Linhaifeng' import time person_list=['alex','wupeiqi','yuanhao','linhaifeng'] def ask_way(person_list): print('-'*60) if len(person_list) == 0: return '没人知道' person=person_list.pop(0) if person == 'linhaifeng': return '%s说:我知道,老男孩就在沙河汇德商厦,下地铁就是' %person print('hi 美男[%s],敢问路在何方' %person) print('%s回答道:我不知道,但念你慧眼识猪,你等着,我帮你问问%s...' %(person,person_list)) time.sleep(3) res=ask_way(person_list) # print('%s问的结果是: %res' %(person,res)) return res res=ask_way(person_list) print(res)
递归特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
堆栈扫盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html
尾递归优化:http://egon09.blog.51cto.com/9161406/1842475
data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35] def binary_search(dataset,find_num): print(dataset) if len(dataset) >1: mid = int(len(dataset)/2) if dataset[mid] == find_num: #find it print("找到数字",dataset[mid]) elif dataset[mid] > find_num :# 找的数在mid左面 print("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid]) return binary_search(dataset[0:mid], find_num) else:# 找的数在mid右面 print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid]) return binary_search(dataset[mid+1:],find_num) else: if dataset[0] == find_num: #find it print("找到数字啦",dataset[0]) else: print("没的分了,要找的数字[%s]不在列表里" % find_num) 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])])