• Python自动化开发课堂笔记【Day05】


    表达式形式的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:UsersAdministratorPycharmProjectspython17期day5a'
    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), '
    ', 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)omes', 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*oow*', 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*oow*')
    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那必须使用后者。

  • 相关阅读:
    LeetCode 1245. Tree Diameter
    LeetCode 1152. Analyze User Website Visit Pattern
    LeetCode 1223. Dice Roll Simulation
    LeetCode 912. Sort an Array
    LeetCode 993. Cousins in Binary Tree
    LeetCode 1047. Remove All Adjacent Duplicates In String
    LeetCode 390. Elimination Game
    LeetCode 1209. Remove All Adjacent Duplicates in String II
    LeetCode 797. All Paths From Source to Target
    LeetCode 1029. Two City Scheduling
  • 原文地址:https://www.cnblogs.com/paodanke/p/6930612.html
Copyright © 2020-2023  润新知