Python自动化开发课堂笔记【Day05】 - Python基础(函数补充,模块,包)

表达式形式的yield

yield的语句形式: yield 1
yield的表达式形式: x=yield

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

协程函数示例

 1 def gen(func):
 2     def wrapper(*args,**kwargs):
 3         res = func(*args,**kwargs)
 4         next(res) #相当于next(g)或者g.send(None)
 5         return res
 6     return wrapper
 7 
 8 @gen
 9 def eater(name):
10     print('%s start to eat' % name)
11     food_list = []
12     while True:
13         food = yield food_list|
14         food_list.append(food)
15         print('%s start to eat %s'% (name,food))
16 
17 g = eater('Albert') #初始化操作,由装饰函数gen对eater函数进行初始化,传入一个空值
18 print(g.send('Apple')) #此时函数挂起在红线出,send执行后,将Apple传给yield,并有yield赋值给food,之后再执行append操作,让后返回food_list
19 print(g.send('Peach'))

模拟 grep -rl 'python' /root 示例

 1 import os
 2 
 3 def init(func):
 4     def wrapper(*args,**kwargs):
 5         res = func(*args,**kwargs)
 6         next(res)
 7         return res
 8     return wrapper
 9 
10 @init
11 def search_dir(target):
12     while True:
13         search_path = yield #将搜索路径赋值给search_path
14         g = os.walk(search_path)#遍历目录下的所有文件夹和子文件夹以及各文件夹下面的文件
15         for par_dir, _, files in g: #遍历列表g中所有的父级文件夹目录和文件
16             for file in files:#遍历文件夹下所有文件
17                 file_abs_path = r'%s\%s', (par_dir, file)#形成绝对路径字符串
18                 target.send(file_abs_path)#将文件绝对路径传值给open_file函数
19 @init
20 def open_file(target):
21     while True:
22         file_abs_path = yield #将文件绝对路径赋值给file_abs_path
23         with open(file_abs_path,'r', encoding='urf-8') as f:
24             target.send((f,file_abs_path))#将文件内容和绝对路径传值给cat_file函数
25 @init
26 def cat_file(target):
27     while True:
28         f, file_abs_path = yield #将yield中文件内容和绝对路径赋值
29         for line in f:#逐行遍历文件内容
30             tag = target.send(line, file_abs_path)#将每行内容和绝对路径传值给grep_line函数进行判断,并返回值tag
31             if tag: #如果返回值tag为True,就停止对该文件剩余行数的遍历,并进行下一文件逐行遍历
32                 break
33 
34 @init
35 def grep_line(target,pattern):
36     tag = False
37     while True:
38         line, file_abs_path = yield tag #将每行内容和绝对路径赋值,并取到返回值tag
39         tag = False #初始化tag
40         if pattern in line:#如果改行内容匹配到目标字符串,返回值tag为True
41             tag = True
42             target.send(file_abs_path)  #将文件绝对路径传值给print函数打印
43 @init
44 def print_file():
45     file_abs_path = yield
46     print(file_abs_path)
47 
48 x = r'C:\Users\Administrator\PycharmProjects\python17期\day5\a'
49 g = search_dir(open_file(cat_file(grep_line(print_file(), 'python'))))
50 print(g)
51 g.send(x)

面向过程的程序设计:是一种流水线式的编程思路,是机械式
  优点:
    程序的结构清晰,可以把复杂的问题简单
  缺点:
    扩展性差
  应用场景:
    linux内核,git,httpd

匿名函数 

匿名函数:用之则弃的函数,基本不会占用内存,不像正常的全局函数,会存活到程序结束

1 def func(x,y):
2     return x+y
3 func(1,2)
4 
5 f=lambda x,y:x+y
6 print(f)
7 print(f(1,2))

内置函数补充

  1. max,min,zip,sorted的用法, 运用到匿名函数的概念

 1 salaries={
 2 'egon':3000,
 3 'alex':100000000,
 4 'wupeiqi':10000,
 5 'yuanhao':2000
 6 }
 7 for i in salaries:
 8     print(i)
 9 print(max(salaries))
10 res=zip(salaries.values(),salaries.keys())
11 
12 print(list(res))
13 print(max(res))
14 
15 def func(k):
16     return salaries[k]
17 
18 print(max(salaries,key=func))
19 print(max(salaries,key=lambda k:salaries[k]))
20 print(min(salaries,key=lambda k:salaries[k]))
21 
22 print(sorted(salaries)) #默认的排序结果是从小到到
23 print(sorted(salaries,key=lambda x:salaries[x])) #默认的排序结果是从小到到
24 print(sorted(salaries,key=lambda x:salaries[x],reverse=True)) #默认的排序结果是从小到到
2. map,reduce,filter函数
 1 l=['alex','wupeiqi','yuanhao']
 2 res=map(lambda x:x+'_SB',l)
 3 print(res)
 4 print(list(res))
 5 
 6 nums=(2,4,9,10)
 7 res1=map(lambda x:x**2,nums)
 8 print(list(res1))
 9 
10 from functools import reduce
11 l=[1,2,3,4,5]
12 print(reduce(lambda x,y:x+y,l,10))
13 
14 l=['alex_SB','wupeiqi_SB','yuanhao_SB','egon']
15 res=filter(lambda x:x.endswith('SB'),l)
16 print(list(res))

递归调用

  1. 定义:在函数调用过程中,直接或间接地调用了函数本身,这就是函数的递归调用

2. 递归效率低,需要在进入下一次递归时保留当前的状态,解决方法是尾递归,但是Python没有,且对递归层级做了限制
  1.必须有一个明确的结束条件
  2.每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  3.递归效率不高,递归层次过多会导致栈溢出。

1 import sys
2 print(sys.getrecursionlimit()) #查看Python可以递归的层数,默认1000,可设置
3 print(sys.setrecursionlimit(1000000)) #设置Pyth可递归层数。最高8000
4 print(sys.getrecursionlimit()) #查看设置结果

  3. 递归的原理

 1 age(5)=age(4)+2
 2 age(4)=age(3)+2
 3 age(3)=age(2)+2
 4 age(2)=age(1)+2
 5 age(1)=18
 6 
 7 age(n)=age(n-1)+2 #n>2
 8 age(n)=18         #n=1 
 9 
10 def age(n):
11     if n == 1:
12         return 18
13     return age(n-1)+2
14 print(age(5))

  4. 递归的应用(二分法)

 1 第一种方式:
 2 raw_lst = [1,5,324,12,67,34,32,879,65,23,4,78,56,2,6,8]
 3 while True:
 4     lst = sorted(raw_lst)
 5     t_num = input('>>>: ')
 6     n = int(t_num)
 7     while True:
 8         if len(lst) // 2 == 0:
 9             print('Nothing found')
10             break
11         elif lst[len(lst) // 2] == n:
12             print('Bingo')
13             break
14         elif lst[len(lst) // 2] > n:
15             lst = lst[:len(lst) // 2]
16         elif lst[len(lst) // 2] < n:
17             lst = lst[len(lst) // 2:]
18 
19 第二种方式:
20 raw_list = [1, 2, 10,33,53,71,73,75,77,85,101,201,202,999,11111]
21 def search_num(target_num, seq):
22     seq = sorted(seq) # 如果列表是无序的情况下需要先进性排序
23     if len(seq) == 0:
24         return 'Not found...'
25     mid_index = len(seq)//2
26     mid_num = seq[mid_index]
27     if mid_num > target_num:
28         seq = seq[:mid_index]
29         search_num(target_num, seq)
30     elif mid_num < target_num:
31         seq = seq[mid_index+1:]
32         search_num(target_num, seq)
33     elif mid_num == target_num:
34         print('Bingo!!!')
35 search_num(33,raw_list)

模块

1. 什么是模块
  一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀
2. 为什么要使用模块
  程序中定义的函数或者变量都会因为python解释器的关闭而丢失,因此通常我们会将程序以文件的方式保存下来方便重复利用。
  为了方便管理越来越多的文件,我们将这些文件归纳为模块,实用的时候就把模块导入到程序中
3. 如何使用模块

 1 # spam模块文件
 2 # -*- coding:utf-8 -*-
 3 # !/usr/bin/python
 4 __all__ = ['money','read1'] #from spam import * 导入的所有变量,类表中只添加所需变量
 5 money = 1000
 6 def read1():
 7     print('spam->read1->money',money)
 8 def read2():
 9     print('spam->read2 calling read1')
10     read1()
11 def change():
12     global money
13     money = 0
14 #spam.py当作脚本执行时,__name__=='__main__'
15 #spam.py当作模块导入时,__name__=='模块名'
16 # print('当前文件的用途是:', __name__)
17 #作用:用于判断当前文件时按照脚本执行还是模块执行
18 if __name__ == '__main__':
19     print('from the spam.py')
20     print('当作脚本执行')
21     change()
22     print(money)
 1 import...导入模块进行的操作:
 2 1. 产生新的名称空间
 3 2. 以新建的名称空间为全局名称空间,执行文件的代码
 4 3. 拿到一个模块名spam,指向spam.py产生的名称空间
 5     
 6 # fortest.py文件
 7 # -*- coding:utf-8 -*-
 8 # !/usr/bin/python
 9 import spam as x #起一个别名作为引用
10 import spam
11 money = 2000 #此money并非spam名称空间中的money
12 print(spam.money) #从spam的名称空间中的money变量值
13 print(x.money) #相同效果
14 spam.read1()
15 spam.read2()
16 spam.change() #修改spam空间中的money变量,任然以spam名称空间定义的为准
17 print(spam.money)
18 
19 from...import...导入模块进行的操作:
20 1. 产生新的名称空间
21 2. 以新建的名称空间为全局名称空间,执行文件的代码
22 3. 直接拿到就是spam.py产生的名称空间的名字
23 
24 优点:方便,不用加前缀
25 缺点: 容易跟当前文件的名称空间冲突
26 
27 from spam import * #将spam中所有内容导入,使用时不用加前缀,慎用,容易和当前名称空间中变量发生冲突
28 可以在模块文件中使用__all__=[]的方法来加以控制所需导入的名称
29 
30 # fortest.py文件
31 # -*- coding:utf-8 -*-
32 # !/usr/bin/python
33 from spam import read1,money,read2,change
34 print(money)
35 read1()
36 money = 10 #从spam取到的money的值已经被重新绑定赋值,但是spam中的money值没有改变
37 print(money)
38 def read1():
39     print('===> from fortest.py read1')
40 read1() #使用当前名称空间中函数定义的功能
41 read2() #与导入方式无关,此函数从哪个名称空间导入,就会任然沿用该空间函数功能,所以调用的仍然是spam中的read1函数

模块搜索路径

顺序:内存空间 -> 内置函数 -> sys.path(从当前路径开始查找)
import sys
print(sys.path) #查看系统路径
如果需要添加的模块和当前文件不在同一个目录中,那么需要将模块的路径添加到sys.path中,才能添加成功
或者将该模块文件添加到site-package文件夹中

re模块

  re.match:尝试从字符串的开始匹配一个模式,如:下面的例子匹配第一个单词。 

re.match的函数原型为:re.match(pattern, string, flags)

第一个参数是正则表达式,这里为"(\w+)\s",如果匹配成功,则返回一个Match,否则返回一个None;

第二个参数表示要匹配的字符串;

第三个参数是标致位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

1 import re
2 text = "JGood is a handsome boy, he is cool, clever, and so on..."
3 m = re.match(r"(\w+)\s", text)
4 if m:
5 print m.group(0), '\n', m.group(1)
6 else:
7 print 'not match'  

  re.search:会在字符串内查找模式匹配,只到找到第一个匹配然后返回,如果字符串没有匹配,则返回None。

re.search的函数原型为: re.search(pattern, string, flags)

每个参数的含意与re.match一样。 

re.match与re.search的区别:re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

1 import re
2 text = "JGood is a handsome boy, he is cool, clever, and so on..."
3 m = re.search(r'\shan(ds)ome\s', text)
4 if m:
5 print m.group(0), m.group(1)
6 else:
7 print 'not search'  

re.sub: 用于替换字符串中的匹配项。下面一个例子将字符串中的空格 ' ' 替换成 '-' :  

 re.sub的函数原型为:re.sub(pattern, repl, string, count)

其中第二个函数是替换后的字符串;本例中为'-'

第四个参数指替换个数。默认为0,表示每个匹配项都替换。

re.sub还允许使用函数对匹配项的替换进行复杂的处理。如:re.sub(r'\s', lambda m: '[' + m.group(0) + ']', text, 0);将字符串中的空格' '替换为'[ ]'。

1 import re
2 text = "JGood is a handsome boy, he is cool, clever, and so on..."
3 print re.sub(r'\s+', '-', text) 

re.split: 可以使用re.split来分割字符串,如:re.split(r'\s+', text);将字符串按空格分割成一个单词列表。

re.findall: 可以获取字符串中所有匹配的字符串。如:re.findall(r'\w*oo\w*', text);获取字符串中,包含'oo'的所有单词。

re.compile: 把正则表达式编译成一个正则表达式对象。可以把那些经常使用的正则表达式编译成正则表达式对象,这样可提高一定的效率。下面是一个正则表达式对象的一个例子:

1 import re
2 text = "JGood is a handsome boy, he is cool, clever, and so on..."
3 regex = re.compile(r'\w*oo\w*')
4 print regex.findall(text)   #查找所有包含'oo'的单词
5 print regex.sub(lambda m: '[' + m.group(0) + ']', text) #将字符串中含有'oo'的单词用[]括起来。

从目录级别来组织模块的,也是通过import引入
  1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法。
  2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)
  3. import导入文件时,产生名称空间中的名字来源于文件,import包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
注意事项:
  1. 关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:
      凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。
  2. 对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
  3. .对比import item 和from item import name的应用场景:如果我们想直接使用name那必须使用后者。

posted @ 2017-06-03 09:23  秋名山藤原豆腐哥  阅读(203)  评论(0编辑  收藏  举报