• 协程,递归,二分法,模块,包,软件开发规范


    协程函数

    yield的一种用法,只是换了一种形式,yield是把函数的结果变成一个生成器,

    def func(count):
        print('start')
        while True:
            yield count
            count +=1
    
    func(10)
    
    #有了yield后,就不会直接产生结果

    g=func(10)
    print(g) # 函数的结果变成了一个生成器

    yield作用:

    1.把函数的执行结果封装好__iter__和__next__,即得到一个迭代器

    2.与return功能类似,都可以返回值,但不同的是,return只能返回一次值,而yield可以返回多次值

    3.函数暂停与再继续运行的状态是由yield保存的

    yield的表达式形式的应用:

    def eater(name):
        print('%s 说:我开动啦' % name)
        while True:
            food=yield    #一碰到yield就暂停住并且把yield后面的返回值返回当作next(ryan_g)的结果
            print('% eat %s' % (name,food))
    
    ryan_g=eater('ryan')  # 函数的执行结果就是一个生成器
    print(ryan_g) #这是一个生成器
    next(ryan_g) # 第一次yield后面没有返回值
    print(next(ryan_g)) #所以返回None
    print('-------------->')
    next(ryan_g) # 从上次暂停的位置继续往后走
    print(next(ryan_g)) # ryan eat None # None

    现在通过yield给food传值

    def eater(name):
        print('%s 说:我开动啦' % name)
    food_list=[] # 用来记录已经上过的菜
    while True: food=yield food_list
    food_list.append(food) print('% eat %s' % (name,food)) ryan_g=eater('ryan')
    #第一阶段:初始化
    next(ryan_g) # 等同于ryan.send(None)
    print('--------->') #ryan说:我开动啦 # --------->
    #第二阶段:给yield传值
    ryan_g.send('骨头') #把'骨头'传给yield,赋值给food,继续往下执行,直到再次碰到yield,然后暂停并且把yield后的返回值当作本次调用的返回值 # ryan eat 骨头
    print(ryan_g.send('骨头')) # ['骨头'] yield把函数暂停,并且把foodlist当作本次调用的返回值
    print('--------->')
    print(ryan_g.send('菜汤')) # ['骨头','菜汤']
    print(ryan_g.send('包子')) #['骨头','菜汤','包子']

    总结:

    传参的3种方式

    1.通过实参传给形参

    2.装饰器的形式,在函数外包一层

    3.在函数内部定义yield,等式的形式,函数执行不会有执行效果,得到一个生成器,用send的方式传值

    好处:

    在用传参的方式时,每次传参都要调用一次,调用完后传值进去,会产生局部名称空间,调用完后结束,下次再调用一次,再申请,再释放

    而现在传一次参数,执行一次函数,通过send,但比起上面的好处是不用重复申请内存空间了,一直是基于上次来执行的,始终用的都是一个函数,

    而且,在函数外部拿到一个函数的生成器,有了这个生成器就可以到处传,传给其他函数,把这些生成器写到另一个函数里,就是两个函数之间的交互

    def eater(name):
        print(' %s 说:我开动啦' % name)
        food_list=[]
        while True:
            food=yield food_list
            food_list.append(food)
            print(' %s eat %s' % (name,food))
    
    def  producer():
        ryan_g=eater('ryan')  #函数的生成器
        next(ryan_g)             # 初始化
        while True:
            food=input('>>: ').strip()
            if not food:continue
            print(ryan_g.send(food))
            
    producer()

    每次都要初始化,现在改为只管send,不管初始化的事情,使用装饰器(使其自动完成初始化--->next(ryan_g)),使 ryan_g=eater('ryan') 执行完的结果直接是 next之后的结果

    def init(func):
        def wrapper(*args,**kwargs):
            g=func(*args,**kwargs)
            next(g)
            return g
        return wrapper
    
    @init
    def eater(name):
        print('%s 说:我开动啦' % name)
        food_list=[]
        while True:
            food=yield food_list
            food_list.append(food)
            print('%s eat %s' % (name,food))
    
    ryan_g=eater('ryan')
    print(ryan_g.send('骨头'))

    面向过程编程

    核心是过程二字,过程即解决问题的步骤

    优点:程序结构清晰,把复杂为提简单化,流程化

    缺点:可扩展性差,一条流水线只是用来解决一个问题

    实现-->grep -rl 'error' /dir/

    建立如下文件,并且在a1.txt,a2.txt,b1.txt中写入error,其余的文件不写入error,随便写别的

    
    
    import os

    def init(func):
    def wrapper(*args,**kwargs):
    g=func(*args,**kwargs)
    next(g)
    return g
    return wrapper

    #第一阶段:找到所有文件的绝对路径
    @init
    def search(target):
    while True:
    filepath = yield
    g=os.walk(filepath)
    for pardir,_,files in g: # 父目录,子目录,文件
    # print(pardir,files)
    for file in files:
    abspath=r'%s\%s' % (pardir,file)
    target.send(abspath)

    #第二阶段:打开文件
    @init
    def opener(target):
    while True:
    abspath=yield
    with open(abspath,'rb') as f:
    target.send((abspath,f))

    #第三阶段:循环读出每一行内容
    @init
    def cat(target):
    while True:
    abspath,f=yield #(abspath,f)
    for line in f:
    res=target.send((abspath,line))
    if res:break

    #第四阶段:过滤
    @init
    def grep(pattern,target):
    tag=False
    while True:
    abspath,line=yield tag
    tag=False
    if pattern in line:
    target.send(abspath)
    tag=True

    #第五阶段:打印该行属于的文件名
    @init
    def printer():
    while True:
    abspath=yield
    print(abspath)

    g = search(opener(cat(grep('error'.encode('utf-8'), printer()))))
    g.send(r'D:PyCharm_Projectsday7a')

    递归调用

    在调用一个函数的过程中,直接或间接的调用了函数本身

    直接调用

    def func():
        print('from func')
        func()
    
    func()

    间接调用

    def foo():
        print('from foo')
        bar()
    
    def bar():
        print('from bar')
        foo()
    
    foo()

    对递归做的限制

    1.必须有一个明确的结束条件

    2.每进入更深一层递归时,问题规模比上次都应有所减少

    3.效率不高

    # 取出列表中的所有元素,for 循环就没办法,因为不知道次数,这里用递归更合适,递归不用关心循环多少层,只需要控制好结束条件即可
    l =[1, 2, [3, [4, 5, 6, [7, 8, [9, 10, [11, 12, 13, [14, 15,[16,[17,]],19]]]]]]] def search(l): for item in l: if type(item) is list: search(item) else: print(item) search(l)

    二分法

    #查找某一个数字是否在这个列表中
    
    l = [1,2,5,7,10,31,44,47,56,99,102,130,240]
    def binary_search(l,num):
        print(l)
    if len(l) == 1:
    if l[0] == num:
    print('find it')
    else:
    print('not exists')
    return mid_index
    =len(l)//2 mid_value=l[mid_index] if num==mid_value: print('find it') return if num > mid_value: l=l[mid_index:] if num < mid_index: l=l[:mid_index] binary_search(l,num) binary_search(l,32)

    模块

    import,导入模块做了哪些事?

    1.执行源文件

    2.产生一个源文件的全局名称空间

    3.在当前位置拿到一个模块名,指向2创建的名称空间

    import ... as ...

    #mysql.py
    
    def sqlparse():
        print('mysql sqlparse')
    #oracle.py
    
    def sqlparse():
        print('oracle sqlparse')
    # test.py
    
    sql_type=input('sql_type: ')
    if sql_type == 'mysql':
        import mysql as sql
    elif sql_type == 'oracle':
        import oracle as sql
    
    sql.sqlparse()      # 统一的调用方式

    from ... import ...

    优点:使用源文件内的名字时无需加前缀,使用方便

    缺点:容易与当前文件的名称空间内的名字混淆

    from ... import *  

    ( *是除了以_开头的,_只对*有用,若是from ... import _money,则无用,也可以导入)

    #spam.py
    print('from the spam.py')
    
    _money
    =1000
    def _read1(): print('spam->read1->money',money) def read2(): print('spam->read2 calling read') read1() def change(): global money money=0
    #from ... import.py
    
    from spam import *
    
    print(money)   # 报错
    # spam.py
    __all__ = ['money','x']     # 只对*起作用,别的函数只能导入__all__定义的变量和函数
    money=1000

    def _read1():
        print('spam->read1->money',money)
    
    def read2():
        print('spam->read2 calling read')
        read1()
    
    def change():
        global money
        money=0
    #from ... import.py
    
    from spam import *
    
    print(money)  
    print(x)

    模块只在第一次导入时才会执行,之后的导入都是直接引用内存已经存在的结果

    import sys
    print('spam' in sys.modules)  #存放的是已经加载到内存中的模块

    模块的搜索路径

    先从内存中找,再从内置模块中找,最后从硬盘中找(sys.path)

    如何区分python文件的两种用途

    1.文件当作脚本运行时,__name__等于__main__

    2.文件当作模块被加载运行时,__name__等于模块名

    Logging模块

    日志级别

    CRITICAL = 50

    ERROR = 40

    WARNING = 30

    INFO = 20

    DEBUG = 10

    import logging    
    
    logging.info('info')
    logging.warning('warning')
    logging.error('error')
    logging.critical('critical')
    # 这种方式日志默认写到了终端上

    把日志写到文件中

    软件开发规范

     ATM ---->项目名
        bin目录----->放执行文件
            start.py    ---> 执行此文件时要保证bin,conf,log,lib,db,core目录下的所有文件都能被找到,因此ATM目录需要加入到环境变量中去
        conf目录--->放配置文件
            settings.py
        log目录
            access.log
        lib目录 ----->存放模块,包,文件,自己开发的功能模块
            glance包
            common.py  --> 模块
        db目录
        core目录 ---> 核心逻辑
            src.py ---->通过start.py来调用核心逻辑
    README ----> 软件的介绍,如何使用
    #src.py   -----> 此文件不能直接运行
    from conf import settings
    def search():
    print('search',settings.x)

    def run(): print('''
    1 查询
    2 购物
    3 转账
    ''')
    while True:
    choice=input('>>: ').strip()
    if not choice:continue
    if choice == '1':
    search()
    elif choice == '2':
    pass
    elif choice == '3';
    pass
    else:
    pass
    #src.py
    
    import sys,os
    
    BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    
    from core import src
    
    if __name__ == '__main__':
        src.run()
    #settings.py
    x=1
  • 相关阅读:
    H5测试
    mysql安装
    HTTP工作过程
    正则表达式常用方法
    20223
    视音频数据处理入门:RGB、YUV像素数据处理
    父母课堂——如何陪伴孩子过一个有意义的寒假
    c语言二维数组
    MobaXterm
    蓝牙介绍
  • 原文地址:https://www.cnblogs.com/Ryans-World/p/7258380.html
Copyright © 2020-2023  润新知