代码改变世界

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.send10

 num就是10y就是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:格式为mapfun,list),就是将后面的可迭代对象的值经过函数处理以后,将函数的返回值作为一个新值放到一个新的可迭代对象中。

egmap(lambda x:x+1,[1,2,3,4,5,6])

reduce:格式为reduce(fun,list,start),迭代取出第二个参数的值,然后和初始值传到第一个参数,返回值继续作为下一次的初始值。

filter:生成一个生成器,迭代第二个参数到第一个参数(函数)中,如果返回true,就可以使用__next__()打印这个值。

maxsalaries,key=func):将前面的结果传给后面的函数作为一个参数,然后将返回的结果来进行max的比较。不过返回的值的类型是直接max前面的值的类型。

递归函数

在函数的调用过程中,直接或间接调用了函数本身,这就是函数的递归调用。

有以下几个注意事项:

1.python中,默认允许递归1000层。

2.递归不能无限递归,要给他手动设置一个结束标志

3.递归函数要等待下一层的结果,所以如果层数过多,函数过大,可能会导致栈溢出。

递归的应用:

二分法

 

模块

模块分为自带模块、自己写的模块、第三方模块。就相当于是一个python文件。导入模块就是导入这个模块的名称空间。

如何使用模块:

1import,可以直接直接导入这个模块的名称空间,然后找到变量对应的值并使用。

导入模块做的事情:

①产生新的名称空间

②以新建的名称空间为全局名称空间,执行文件的代码

③拿到了一个模块名,指向了spam.py

2from...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’]

下面这个例子同理: