bai|boyang

导航

 

今天学习的内容如下:

1.协程函数

2.递归

3.匿名函数lambda

4.内置函数(map,reduce,filter,max,min,zip,sorted)

5.面向过程编程与函数编程

6.模块与包的使用

7.常用模块

下面开始上节课的复习:

1.函数对象(第一类对象):

1.1 函数可以被当成数据来传递

1.2 可以被引用

1.3 可以当作参数传递给另一个函数

1.4 可以当作函数的返回值

1.5 可以当作容器类型的元素

2.函数的嵌套

2.1 函数的嵌套调用(在调用函数的过程中 有调用了其他的函数)

2.2 函数的嵌套定义(在定义函数时,又实用def关键字定义了其他函数)

3.名称空间和作用域

3.1内置名称空间(变量的定义 都是绑定操作,都没有储值的操作)(python解释器启动的时候产生)

3.2 全局名称空间(文件级别的)(打开文件的时候产生)

3.3 局部名称空间(函数内部定义的名字)(调用函数的时候产生)

3.4 全局作用域(全局名称空间和内置名称空间)

3.5 局部作用域(局部名称空间)

4 闭包

4.1 定义在函数内部的函数

4.2 该内部函数包含对外部作用域而不是对全局作用域的引用

可以用来惰性计算

5. 装饰器

开放封闭原则,对修改是封闭的,对扩展是开放的

装饰器可以是任意可调用的对象

装饰器并不仅限于函数

被装饰的对象也是任意可调用对象

装饰器遵循的原则:

  不修改被装饰对象的源代码,不修改被装饰对象的调用方式

6 迭代器

迭代重复上次的过程,每一次迭代都是基于上一次迭代的结果继续进行

可迭代对象:obj__iter__方法

迭代器对象:obj__iter__ obj__next__方法

提供了一种不需要依赖于索引的迭代方式

for 循环的原理是 首先执行iter方法,然后用next方法去得到

迭代器的优点和缺点:

提供了一种不依赖于索引的迭代方式

节省内存

缺点:

无法获取长度

一次性的

7 生成器

函数体内包含yield,函数的执行结果是生成器对象,本质是迭代器,把函数的执行结果做成了迭代器

返回多次值,return只能返回一次值

可以暂停 挂起函数的执行,下一次 基于上次的执行状态继续执行

8 内置函数

今天上课的内容

1.yield的语句形式: yield 1

2.yield的表达式形式: x=yield(额外的功能,传参数)

例子:

 1 def eater(name):
 2   print('%s ready to eat' %(name))
 3   while True:
 4       food = yield
 5      print('%s start to eat %s' %(name,food))
 6 
 7 g = eater('alex')
 8 next(g)
 9 
10 g.send('手指头')
11 g.send('脚趾头')

3. 加一个装饰器,实现初始化的功能

 1 def deco(func):
 2   def wrapper(*args,**kwargs):
 3      res = func(*args,**kwargs)
 4      next(res)
 5      return res
 6   return wrapper
 7 
 8 @deco
 9 def eater(name):
10   print('%s ready to eat' %(name))
11   while True:
12      food = yield
13      print('% start eat %s' %(name,food))

4. 模拟菜单功能

 

 1 def deco(func):
 2     def wrapper(*args,**kwargs):
 3         res = func(*args,**kwargs)
 4         next(res)
 5         return res
 6     return wrapper
 7 
 8 @deco
 9 def eater(name):
10     print('%s ready to eat' %(name))
11     food_list = []
12     while True:
13         food = yield food_list
14         food_list.append(food)
15         print('%s start eat %s' %(name,food))
16 
17 g = eater('alex')
18 print(g.send('egon1'))
19 print(g.send('egon2'))

5. x=yield的功能

5.1 g.send('111'),先把111传值给yield,由yield赋值给x,然后再往下执行,直到再次碰到yield,然后把yield后的返回值返回

6. yield的应用

例如:grep -rl 'python' /root(找到/root目录下所有文件中包含python内容的文件,把文件名返回)

 1 import os
 2 
 3 def deco(func):
 4     def wrapper(*args,**kwargs):
 5         res = func(*args,**kwargs)
 6         next(res)
 7         return res
 8     return wrapper
 9 
10 @deco
11 def search(target):
12     while True:
13         serach_path = yield
14         g=os.walk(serach_path)
15         for par_dir,_,files in g:
16             for file in files:
17                 file_abs_path=r'%s\%s' %(par_dir,file)
18                 # print(file_abs_path)
19                 target.send(file_abs_path)
20 
21 
22 @deco
23 def opener(target):
24     while True:
25         file_abs_path=yield
26         with open(file_abs_path,encoding='utf-8') as f:
27             target.send((file_abs_path,f))
28 @deco
29 def cat(target):
30     while True:
31         file_abs_path,f = yield
32         for line in f:
33             target.send((file_abs_path,line))
34 @deco
35 def grep(target,pattern):
36     while True:
37         line = yield
38         if pattern in line:
39             target.send(file_abs_path)
40 
41 @deco
42 def printer():
43     while True:
44 
45         file_abs_path = yield
46         print(file_abs_path)
47         
48 g = search(opener(cat(grep(printer),'python')))
49 g.send('/root')

7. 面向过程的程序设计

是一种流水线式的编程思路,是机械式的,优点是:程序的结构清晰,可以把复杂的问题简单化,明细化。缺点是:扩展性差

应用场景:linux的内核,git,httpd都是面向过程方式写的

8. 模块与包

什么模块,一个py文件 就是一个模块,一个模块就是一个包含了python定义和申明的文件。

为什么要使用模块:方便管理,实现了功能的重复利用

引用的两种方式

import ...

from ... import ...(优点:不用加前缀,缺点:容易和当前的重名)

导入模块干的事:

1.产生新的名称空间

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

3.拿到一个模块名,指向导入的模块.py产生的名称空间

spam.money(引用模块的值)

spam.read1(拿到read1的内存地址,然后可以执行)

import ... as ... (起别名,一行也可以导入多个,通过逗号隔开)

从哪个文件来就以哪个文件的环境变量为准

__all__=[](和from import * 一起使用,列表里面必须是字符串,控制导入的值)

9. __name__

__file__:绝对路径

1.当作脚本执行的时候__name__ == '__main__'

2.当作模块导入: __name__ == 模块名

1 if __name == '__main__':
2   print('当作脚本执行')

 10. 模块的搜索路径

先从内存里面找,然后去内置的里面找,然后去sys.path里面去找(sys.path,就是一个列表)

11. 包

1. 无论是import形式还是from...import形式,凡是再导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉,这都是关于包才有的导入语法

2. 包是目录级别的(文件夹级),文件夹是用来组成py文件的(包的本质就是一个包含__init__.py文件的目录)

3. import导入文件的时候,产生的名称空间中的名字来源于文件,import 包,产生的名称空间中的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件

ps:包A和包B下有同名的模块也不会冲突,如A.a和B.a来自于两个命名空间

11.1 注意事项

1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。

2.对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。

3.对比import item 和from item import name的应用场景:
如果我们想直接使用name那必须使用后者

11.2 __init__.py

不管是哪种方式,只要是第一次导入包或者是包的任何其他部分,都会依次执行包下的__init__.py文件(我们可以在每个包的文件内都打印一行内容来验证一下),这个文件可以为空,但是也可以存放一些初始化包的代码。

 11.3 绝对导入和相对导入

我们的最顶级包glance是写给别人用的,然后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式:

绝对导入:以glance作为起始

相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)

例如:我们在glance/api/version.py中想要导入glance/cmd/manage.py

 

注意:在使用pycharm时,有的情况会为你多做一些事情,这是软件相关的东西,会影响你对模块导入的理解,因而在测试时,一定要回到命令行去执行,模拟我们生产环境,你总不能拿着pycharm去上线代码吧!!!

 

特别需要注意的是:可以用import导入内置或者第三方模块(已经在sys.path中),但是要绝对避免使用import来导入自定义包的子模块(没有在sys.path中),应该使用from... import ...的绝对或者相对导入,且包的相对导入只能用from的形式。

比如我们想在glance/api/versions.py中导入glance/api/policy.py,有的同学一抽这俩模块是在同一个目录下,十分开心的就去做了,它直接这么做

1 #在version.py中
2 
3 import policy
4 policy.get()

 

没错,我们单独运行version.py是一点问题没有的,运行version.py的路径搜索就是从当前路径开始的,于是在导入policy时能在当前目录下找到

但是你想啊,你子包中的模块version.py极有可能是被一个glance包同一级别的其他文件导入,比如我们在于glance同级下的一个test.py文件中导入version.py,如下

 1 from glance.api import versions
 2 
 3 '''
 4 执行结果:
 5 ImportError: No module named 'policy'
 6 '''
 7 
 8 '''
 9 分析:
10 此时我们导入versions在versions.py中执行
11 import policy需要找从sys.path也就是从当前目录找policy.py,
12 这必然是找不到的
13 '''                                                                                                        
posted on 2017-06-06 18:00  bai|boyang  阅读(228)  评论(0编辑  收藏  举报