上节回顾
函数对象
函数可以被当成数据来传递
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
reduce
filter
max(salaries,key=func):将前面的结果传给后面的函数作为一个参数,然后将返回的结果来进行max的比较。不过返回的值的类型是直接max前面的值的类型。
高阶函数:如果函数的一个参数是一个函数,或者返回的是一个函数,那他就是高阶函数。
map:传送两个参数,第一个参数是一个函数对象,后面你的是一个可迭代对象。
map(lambda x:x+’sb’,list)
他会一次for循环后面的对象,然后传给前面的fun,然后他会将处理过的东西插入到新的map对象(可以理解为列表)中,最后返回这个MAP函数。
reduce:传三个参数,函数,可迭代对象,初始值。
如果你不给初始值,他会把可迭代对象的第一个值作为初始值,然后迭代后面的东西,把他和初始值赋给前面的函数得到结果作为结果和继续迭代的东西进行操作。
filter:传两个参数,第一个参数?一个函数,第二个参数是一个可迭代对象。
filter (lambda x:x.endswith(‘SB’),l)
递归函数:在函数的调用过程中,直接或间接调用了函数本身,这就是函数的递归调用。
python里面有一个递归锁。默认可以递归1000层
可以用
来设。
递归函数分为两个过程:递推和回溯。
递归的注意事项:
1.递归必须有一个明确的结束条件。
2.每次进入更深一层递归的时候,问题规模相比上次递归都应该有所减少。
3.递归效率不高,在python中递归层数过多会导致栈溢出。
递归的应用:
二分法
模块:自带模块、自己写的模块、第三方模块。
如何使用模块:
1、import
2、
导入模块做的事情:
1、产生新的名称空间
2、以新建的名称空间为全局名称空间,执行文件的代码
3、拿到了一个模块名,指向了spam.py。
还有一种方式导入:
from 导入
这个也是一个模块导入:
1.产生新的名称空间。
2.以新的名称空间为全局名称空间,执行文件的代码。
3.直接拿到spam.py产生的名称空间的名字
4.会跟当前文件的变量冲突
from导入的方式就是比import调用的方便一点。
执行导入的方法,还是以原文件的变量为准。
from spam import *(直接导入所有的变量)
直接导入模块内的__all__列表里面的所有定义的变量。
__name__:当做脚本执行,他的值是__main__,被当做模块导入的时候__name__=spam。
所以一般文件最下面都是
这样就是被当做模块导入的时候就不会执行,而自己测试模块的时候就可以在下面弄。
import的搜索路径:
先找内存→然后找内置→然后找sys.path。
我们可以自己添加sys.path的东西。
sys.path.insert(0,r’C:\.....’)
导入包:
1.无论是import形式还是from...import形式,凡事在导入语句中遇到带点的,就要知道,这是关于包才有的导入语法。
点的左边必须是一个包,右边有可能是包也有可能是模块。
import 包的话就是相当于导入了glance下的__init__.py
调用包的话就相当于是在调包下面的init文件。
绝对导入:导入包的时候 在glance下的__init__下面使用from glance.xx import xxx
这样 和glance一级的文件就可以直接找这个包。
from ..db import xxxx
from ...db import xxx
使用相对路径是为了方便以后包名字更改的问题。
*的特殊用法
可以直接导入模块。这是另外一种用法。
RE模块:
导入re模块,import re
正则的在线调试工具:tool.oschina.net/regex/
re.findall(partten,str)
元字符:
\w:匹配字母数字及下划线。
.可以匹配任意字符,但是没法匹配换行符\n
[]:匹配其中任意一个字符,可以匹配\n。
这里的?是转义的意思,不是0-1次,是将贪婪匹配转换为非贪婪匹配。
|:
匹配成功了只会返回括号里面的内容。
这样转义一下就好了。
下面这个例子同理: