python第五天:协程,匿名函数,递归函数,模块导入,re模块
2017-06-03 10:13 明月照花眠 阅读(183) 评论(1) 收藏 举报上节回顾
函数对象
函数可以被当成数据来传递
def func():
pass
1.可以被引用。f=fun
2.可以当做参数传递给另外一个函数
3.可以作为函数的返回值
4.可以当做容器类型的元素
比如用户有10多个参数,我们不需要写10多个if判断。可以写一个字典。
dic = {‘func1’:func1,’func2’:func2}
调用个时候就用dic[‘func1’]()
函数的嵌套
函数的嵌套可以分为两种:嵌套定义和嵌套调用。
嵌套调用:函数的执行过程中调用其他的函数,可以更加细化的功能。
嵌套定义(在定义函数时,又使用def关键字定义了其他函数):我们可以在闭包函数和装饰器里面用到他。
名称空间和作用域
内置名称空间(py解释器运行了就定义了这个空间)
全局名称空间(文件执行的时候定义这个空间,别的文件调用需要import这个变量)
局部名称空间(函数调用的时候,函数执行完就释放了)
全局作用域:全局有效,在任何位置都能被访问到,存活到文件执行结束。
局部作用域:局部有效,只能在函数内部被访问到,在函数执行结束后,就释放了。
闭包函数
是一个定义在函数内部的函数,不受外界变量影响,调用外面的函数,直接返回闭包函数对象。
def f1():
def f2():
print(x)
return f2
f=f1()
f()
装饰器
函数对扩展是开放的,对修改是封闭的。为了满足这个特性就用到了装饰器。
装饰器本身可以是任意可调用对象,可以装饰任意可调用对象。
装饰器要遵循的原则:
1、不修改被装饰对象的源代码
2、不修改被装饰对象的调用方式(包括返回值,参数)
迭代器
迭代:重复上一次过程,每一次重复都基于上一次执行的结果而继续进行。
可迭代对象:有__iter__方法的就叫可迭代对象。
迭代器对象:有__next__方法的就是迭代器对象。
为何要有迭代器:提供了一种不依赖于索引的迭代方式。
迭代器的优缺点:提供一种不依赖于索引的迭代方式、节省内存。
无法获取长度,一次性的,只能取下一个。
生成器
函数体内含有yield关键字,该函数执行的结果就是生成器。
生成器本质就是迭代器,所以yield的功能就是:
1.把函数的执行结果做成迭代器。
2.yield相当于可以在函数里面写多个的return。
3.生成器可以通过send方法给yield赋值,然后yield再给别的变量赋值。
比如 num=yield 3
y=x.send(10)
那num就是10,y就是3。
上课内容
协程函数
协程函数就是给生成器传送参数,让每次迭代过程都根据这个参数传送不同的结果。
yield可以往函数内传值。
def eater(name):
print(“ready to eat”%name)
while True:
food = yield
print(“start to eat ”%food)
g=eater(‘alex’)
next(g)
g.send(‘苹果’)
生成器的开始必须要传送的NONE。
可以用装饰器来生成一个不需要传NONE的。
def zhuangshi(fun):
def fun1(*args,**kwargs):
f = fun(*args,**kwargs)
f.send(None)
return f
return fun1
@zhuangshi
def eater(name):
print("ready to eat%s"%name)
food_list=[]
while True:
food_list.append(food)
food = yield food_list
print("%s start to eat %s"%(name,food))
g=eater('alex')
g.send('苹果')
总结:yield不光有return的功能,可以通过shengcheng.send()函数给他传参数。同时也可以返回yield后面的值。
面向过程的编程方法
1.编写一个能返回程序,并且将
os.walk用法
传入一个目录,返回一个元组,里面有3个元素。(父目录,子目录列表,子文件列表)
然后对其下面的子目录递归的执行walk,返回多个元组。
类似这种情况:
我们可以通过编写多个函数生成器彼此嵌套:找到文件名→打开文件→找到行→判断行→打印文件名这个过程来写一个和grep -rl类似的程序。
这种程序是一个类似流水线式的编程思路,是机械式的。
优点:程序结构清晰,可以把复杂的问题简单化。缺点是扩展性差,牵一发而动全身。
匿名函数lambda
我们把函数
def f1(x,y):
z=x+y
return z
改写成匿名函数,首先用lambda替换def ,去掉f1(),将函数主体和return替换成:即可,将z写成x+y。
lambda x,y:x+y
一些能用到匿名函数的内置
map:格式为map(fun,list),就是将后面的可迭代对象的值经过函数处理以后,将函数的返回值作为一个新值放到一个新的可迭代对象中。
eg:map(lambda x:x+1,[1,2,3,4,5,6])
reduce:格式为reduce(fun,list,start),迭代取出第二个参数的值,然后和初始值传到第一个参数,返回值继续作为下一次的初始值。
filter:生成一个生成器,迭代第二个参数到第一个参数(函数)中,如果返回true,就可以使用__next__()打印这个值。
max(salaries,key=func):将前面的结果传给后面的函数作为一个参数,然后将返回的结果来进行max的比较。不过返回的值的类型是直接max前面的值的类型。
递归函数
在函数的调用过程中,直接或间接调用了函数本身,这就是函数的递归调用。
有以下几个注意事项:
1.在python中,默认允许递归1000层。
2.递归不能无限递归,要给他手动设置一个结束标志
3.递归函数要等待下一层的结果,所以如果层数过多,函数过大,可能会导致栈溢出。
递归的应用:
二分法
模块
模块分为自带模块、自己写的模块、第三方模块。就相当于是一个python文件。导入模块就是导入这个模块的名称空间。
如何使用模块:
1、import,可以直接直接导入这个模块的名称空间,然后找到变量对应的值并使用。
导入模块做的事情:
①产生新的名称空间
②以新建的名称空间为全局名称空间,执行文件的代码
③拿到了一个模块名,指向了spam.py。
2、from...import... 导入
这个也是一个模块导入:
①产生新的名称空间。
1.以新的名称空间为全局名称空间,执行文件的代码。
2.直接拿到spam.py产生的名称空间的名字
4.会跟当前文件的变量冲突
from spam import *(直接导入所有的变量)
直接导入模块内的__all__列表里面的所有定义的变量。
模块测试
如果想测试自己的模块,在最下面就加入一行if __name__ = main():,这样别人在导入的时候就不会执行下面的测试代码。因为在导入的时候会显示__name__=函数名。
导入的优先级
先找内存→然后找内置→然后找sys.path。
我们可以自己添加sys.path的东西,sys.path.insert(0,r’C:\.....’)
包
导入包
1.无论是import形式还是from...import形式,凡事在导入语句中遇到带点的,就要知道,这是关于包才有的导入语法。点的左边必须是一个包,右边有可能是包也有可能是模块。
2.import导入文件的时,产生名称空间中的名字来源于文件,import包,产生的名称孔家你的名字同样来源于文件,即包下的__init__.py,导入包的本质就是在导入该文件。
例子:我们以glance包为例,和glance同级的文件,导入glance包的时候,就相当于是在导入glance的__init__文件。如果我们在这个文件下面使用from glance.xx import xxx,这样这个文件就可以直接调用这个方法。
相对路径和绝对路径
.当前目录
..上级目录
...上上级目录
一般导入的时候都使用相对路径,方便以后更改包的名字。
*的特殊用法
*是直接导入文件下面__all__列表的值。
可以直接导入模块。这是另外一种用法。
RE模块
导入re模块,import re
正则的在线调试工具:tool.oschina.net/regex/
re.findall(partten,str)
元字符:
\w:匹配字母数字及下划线。
.可以匹配任意字符,但是没法匹配换行符\n
[]:匹配其中任意一个字符,可以匹配\n。
贪婪匹配与非贪婪匹配
#贪婪匹配
re.findall(‘a.*c’,’ac abc aex a1c’)
#非贪婪匹配
re.findall(‘a.*?c’,’ac abc aex a1c’)
这里的?是转义的意思,不是0-1次,是将贪婪匹配转换为非贪婪匹配。
|和?:
re.findall(‘compan(y|ies)’,’Too many conpanies ,my conpany’
[‘ies’,’y’]
直接使用|做或匹配,他只返回括号里面里面的值。
我们使用这种方法就直接返回所有的值:
re.findall(‘compan(?:y|ies)’,’Too many conpanies ,my conpany’
[‘companies’,’conpany’]
下面这个例子同理:
浙公网安备 33010602011771号