Python学习之路6☞函数,递归,内置函数
一python中的函数
函数是逻辑结构化和过程化的一种编程方法。
python中函数定义方法: def test(x):
"The function definitions"
x+=1
return x def:定义函数的关键字
test:函数名
():内可定义形参
"":文档描述(非必要,但是强烈建议为你的函数添加描述信息)
x+=1:泛指代码块或程序处理逻辑
return:定义返回值 调用运行:可以带参数也可以不带
函数名()
二 为何使用函数
背景提要
现在老板让你写一个监控程序,监控服务器的系统状况,当cpu\memory\disk等指标的使用量超过阀值时即发邮件报警,你掏空了所有的知识量,写出了以下代码
while True:
if cpu利用率 > 90%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接 if 硬盘使用空间 > 90%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接 if 内存占用 > 80%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接
上面的代码实现了功能,你这个重复代码太多了,每次报警都要重写一段发邮件的代码,太low了,这样干存在2个问题:
- 代码重复过多,一个劲的copy and paste不符合高端程序员的气质
- 如果日后需要修改发邮件的这段代码,比如加入群发功能,那你就需要在所有用到这段代码的地方都修改一遍
其实很简单,只需要把重复的代码提取出来,放在一个公共的地方,起个名字,以后谁想用这段代码,就通过这个名字调用就行了,如下
def 发送邮件(内容)
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭连接 while True: if cpu利用率 > 90%:
发送邮件('CPU报警') if 硬盘使用空间 > 90%:
发送邮件('硬盘报警') if 内存占用 > 80%:
发送邮件('内存报警')
总结使用函数的好处:
1.代码重用
2.保持一致性,易维护
3.可扩展性
三 函数和过程
过程定义:过程就是简单特殊没有返回值的函数
这么看来我们在讨论为何使用函数的的时候引入的函数,都没有返回值,没有返回值就是过程,没错,但是在python中有比较神奇的事情
def test01():
msg='hello The little green frog'
print msg def test02():
msg='hello WuDaLang'
print msg
return msg t1=test01() t2=test02() print 'from test01 return is [%s]' %t1
print 'from test02 return is [%s]' %t2
总结:当一个函数/过程没有使用return显示的定义返回值时,python解释器会隐式的返回None,
所以在python中即便是过程也可以算作函数。
def test01():
pass def test02():
return 0 def test03():
return 0,10,'hello',['alex','lb'],{'WuDaLang':'lb'} t1=test01()
t2=test02()
t3=test03() print 'from test01 return is [%s]: ' %type(t1),t1
print 'from test02 return is [%s]: ' %type(t2),t2
print 'from test03 return is [%s]: ' %type(t3),t3
总结:
返回值数=0:返回None
返回值数=1:返回object
返回值数>1:返回tuple
四 函数是第一类对象
在python中所有的名字都没有储值功能
函数是第
def foo():
print("yyp")
f1=foo
f1()
# 输出结果:
yyp
可以当做参数
def foo():
print("tom") def func(msg):
print(msg)
msg() func(foo)
输出结果:
<function foo at 0x00000000020D3E18>
tom
可以当做返回值
def foo():
print("tom") def func(msg):
return msg f=func(foo)
print(f)
f()
输出结果:
<function foo at 0x0000000002423E18>
tom
可以当做容器类型的一个元素
def foo():
print("tom") func_dic={
'foo':foo
}
输出结果:
tom
一类对象指的是:函数可以被当做数据来处理被引用
五 函数参数
1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
3.位置参数和关键字(标准调用:实参与形参位置一一对应;关键字调用:位置无需固定)
4.默认参数
5.参数组
六 局部变量和全局变量
在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
name='lhf' def change_name():
print('我的名字',name) change_name() def change_name():
name='帅了一笔'
print('我的名字',name) change_name()
print(name) def change_name():
global name
name='帅了一笔'
print('我的名字',name) change_name()
print(name)
七 前向引用之'函数即变量'
def action():
print 'in the action'
logger()
action()
报错NameError: global name 'logger' is not defined def logger():
print 'in the logger'
def action():
print 'in the action'
logger() action() def action():
print 'in the action'
logger()
def logger():
print 'in the logger' action()
八 嵌套函数和作用域
看上面的标题的意思是,函数还能套函数?of course
name = "yyp" def change_name():
name = "yyp2" def change_name2():
name = "yyp3"
print("第3层打印",name) change_name2() #调用内层函数
print("第2层打印",name) change_name()
print("最外层打印",name)
此时,在最外层调用change_name2()会出现什么效果?
没错, 出错了, 为什么呢?
作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变
例一:
name='yyp' def foo():
name='sy'
def bar():
print(name)
return bar func=foo()
func() 例二:
name='yyp' def foo():
name='sy'
def bar():
name='tom'
def tt():
print(name)
return tt
return bar func=foo()
func()()
九 递归调用
def calc(n):
print(n)
if int(n/2) ==0:
return n
return calc(int(n/2)) calc(10) 输出:
10
5
2
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)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
链接:堆栈扫盲
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)
二分查找
十 匿名函数
匿名函数就是不需要显式的指定函数
#这段代码
def calc(n):
return n**n
print(calc(10)) #换成匿名函数
calc = lambda n:n**n
print(calc(10))
匿名函数主要是和其它函数搭配使用的呢,如下
l=[3,2,100,999,213,1111,31121,333]
print(max(l)) dic={'k1':10,'k2':100,'k3':30} print(max(dic))
print(dic[max(dic,key=lambda k:dic[k])])
res = map(lambda x:x**2,[1,5,7,4,8])
for i in res:
print(i) 输出
1
25
49
16
64
十一 函数式编程
函数式编程:
http://egon09.blog.51cto.com/9161406/1842475
11 高阶函数
满足俩个特性任意一个即为高阶函数
1.函数的传入参数是一个函数名
2.函数的返回值是一个函数名
array=[1,3,4,71,2] ret=[]
for i in array:
ret.append(i**2)
print(ret) #如果我们有一万个列表,那么你只能把上面的逻辑定义成函数
def map_test(array):
ret=[]
for i in array:
ret.append(i**2)
return ret print(map_test(array)) #如果我们的需求变了,不是把列表中每个元素都平方,还有加1,减一,那么可以这样
def add_num(x):
return x+1
def map_test(func,array):
ret=[]
for i in array:
ret.append(func(i))
return ret print(map_test(add_num,array))
#可以使用匿名函数
print(map_test(lambda x:x-1,array)) #上面就是map函数的功能,map得到的结果是可迭代对象
print(map(lambda x:x-1,range(5)))
map函数
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))
reduce函数
#电影院聚集了一群看电影bb的傻逼,让我们找出他们
movie_people=['alex','wupeiqi','yuanhao','sb_alex','sb_wupeiqi','sb_yuanhao'] def tell_sb(x):
return x.startswith('sb') def filter_test(func,array):
ret=[]
for i in array:
if func(i):
ret.append(i)
return ret print(filter_test(tell_sb,movie_people)) #函数filter,返回可迭代对象
print(filter(lambda x:x.startswith('sb'),movie_people))
filter函数
#当然了,map,filter,reduce,可以处理所有数据类型 name_dic=[
{'name':'alex','age':1000},
{'name':'wupeiqi','age':10000},
{'name':'yuanhao','age':9000},
{'name':'linhaifeng','age':18},
]
#利用filter过滤掉千年王八,万年龟,还有一个九千岁
def func(x):
age_list=[1000,10000,9000]
return x['age'] not in age_list res=filter(func,name_dic)
for i in res:
print(i) res=filter(lambda x:x['age'] == 18,name_dic)
for i in res:
print(i) #reduce用来计算1到100的和
from functools import reduce
print(reduce(lambda x,y:x+y,range(100),100))
print(reduce(lambda x,y:x+y,range(1,101))) #用map来处理字符串列表啊,把列表中所有人都变成sb,比方alex_sb
name=['alex','wupeiqi','yuanhao'] res=map(lambda x:x+'_sb',name)
for i in res:
print(i)
总结
十二 内置函数
字典的运算:最小值,最大值,排序
salaries={
'egon':3000,
'alex':100000000,
'wupeiqi':10000,
'yuanhao':2000
} 迭代字典,取得是key,因而比较的是key的最大和最小值
>>> max(salaries)
'yuanhao'
>>> min(salaries)
'alex' 可以取values,来比较
>>> max(salaries.values())
>>> min(salaries.values())
但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键
>>> max(salaries,key=lambda k:salary[k])
'alex'
>>> min(salaries,key=lambda k:salary[k])
'yuanhao' 也可以通过zip的方式实现
salaries_and_names=zip(salaries.values(),salaries.keys()) 先比较值,值相同则比较键
>>> max(salaries_and_names)
(100000000, 'alex') salaries_and_names是迭代器,因而只能访问一次
>>> min(salaries_and_names)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence sorted(iterable,key=None,reverse=False)
最新文章
- 协同开发中SVN的使用建议
- Ajax&;json
- Waiting Processed Cancelable ShowDialog (Release 2)
- [wechall] Time to Reset (Exploit, Coding, PHP)
- setTimeout()和setInterval() 何时被调用执行
- SQL Server 2005使用作业设置定时任务(转)
- IntelliJ IDEA 15 显示工具栏及底部周边工具栏
- Linux下glui 的安装,以及错误解决
- golang中channel的超时处理
- Prime Palindrome Golf
- Cocos2dx 3.0 过渡篇(三十一)ValueVector和Vector不得不说的故事
- Hibernate 系列教程13-继承-鉴别器与内连接相结合
- HDU 2859 Phalanx
- [自制操作系统] 图形界面&VBE工具&MMIO显存&图形库/字库
- swust oj 983
- 一种表达式语言的解析引擎JEXL简单使用
- oracle 索引扫描类型的分类与构造
- CSS 尺寸 (Dimension) 实例
- asdasda
- 【Jmeter自学】Jmeter性能测试(四)
热门文章
- 前端(Node.js)(2)-- Node.js开发环境配置
- Java问题解读系列之IO相关---Java深拷贝和浅拷贝
- tesseract训练手写体
- Neo4j系列-简介及应用场景
- 出现$(#form).validate is not a function的问题
- Nginx 函数解析之ngx_http_get_forwarded_addr_internal
- 微信小程序-- WXML语法
- 微信小程序开发之图片等比例缩放 获取屏幕尺寸图片尺寸 自适应
- springboot整合neo4j
- DirectX11笔记(二)--Direct3D初始化1之基本概念