python 第五弹

 

博客05

python 继续走坑五

函数

python的递归调用
    递归调用: 就是函数在无限的调用自身,但是这个也是有限制的.
    在前面我们了解到,函数可以当做一个参数,可以在内部调用别的函数,现在我们在自己的函数里来调用自己

            def foo(n):
                print(n)
                if int(n/2) ==0:
                    return n
                return foo(int(n/2))

            calc(10)

    递归特性:
        1. 必须有一个明确的结束条件
        2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
        3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当
        进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用
        的次数过多,会导致栈溢出)

    查看可以允许递归的次数(默认是1000)
        import  sys
        print(sys.getrecursionlimit())
    当然可以修改了,但是这也增加了程序的危险性
        print(sys.setrecursionlimit(1000000))

     例子: 最常见的就是二分法的应用了,查找一个数字在不在这个序列里,这个序列是按照从小到大的顺序排列
        l = [1, 2, 10,33,53,71,73,75,77,85,101,201,202,999,11111]   
        def search(seq,find_num):
            if len(seq) == 0:
                print('Not esxit!!!')
                return
            mid_index =  len(seq)//2
            mid_num = seq[mid_index]
            if find_num >  mid_num:
                #说明在序列的右边
                seq=seq[mid_num+1:]
                search(seq,find_num)
            elif find_num <  mid_num:
                #说明在序列的左边
                seq=[:mid_num]
                search(seq,find_num)
            else:
                print('Find It')

         search(l,33)

yield 函数的另一种用法

        先了解一下生成器
  • Generators
    Generators are iterators, but you can only iterate over them once. It’s because they do not store all the values in memory, they generate the values on the fly:

        >>> mygenerator = (x*x for x in range(3))
        >>> for i in mygenerator:
        ...    print(i)
        0
        1
        4
    
  • It is just the same except you used () instead of []. BUT, you cannot perform for i in mygenerator a second time since generators can only be used once: they calculate 0, then forget about it and calculate 1, and end calculating 4, one by one.

        yield就像return,接受函数的传递,并返回一个生成器
        >>> def createGenerator():
        ...    mylist = range(3)
        ...    for i in mylist:
        ...        yield i*i
        ...
        >>> mygenerator = createGenerator() # create a generator
        >>> print(mygenerator) # mygenerator is an object!
        <generator object createGenerator at 0xb7555c34>
        >>> for i in mygenerator:
        ...     print(i)
        0
        1
        4
    
        这个函数在调用的时候,你写里面的代码不会运行,这个函数返回一个生成器.
        当for 在调用这个函数产生的生成器的时候,他会运行你函数代码里面的的内容,当遇到yield的时候,他会返回第一个循环里面产生 的值
    
  • yield

        yield的语句形式: yield 1
        yield的表达式形式: x=yield
    
        return只能返回一个值,yiled能返回多次值
        #yiled能把一个函数变成一个生成器
        #yiled能保存当前程序的运行状态
        #yiled能作为一个语句形式存在  yield n
        #yiled能作为一个表达式形式存在  n=yield    可以用send()赋值给n
    
        #携程函数
    
        def eater(name):
            print(name)
            while True:
                food=yield    #因为碰到yield就停止,所以上面加了while True
                print ('you eat %s' %food)
    
        g=eater('liukang')
    


    g.next()
    g.send(‘菜’)
    ##必须先初始化一下,否会报错”TypeError: can’t send non-None value to a just-started generator”
    报错如上图

        但是我们可以用装饰器来解决这个问题
    
        def init_send(func):
            def wrapper(*args,**kwargs):
                res=func(*args,**kwargs)
                res.__next()
                return res
            return wrapper
    
        @init_send
        def eater(name):
            print(name)
            while True:
                food=yield    #因为碰到yield就停止,所以上面加了while True
                print ('you eat %s' %food)
    
        g=eater('liukang')
        g.send('菜')   ##这里我没有进行初始化,因为装饰器解决了
        或者使用g.netx('菜')
        food=yield
        g.send('菜'),先把'菜'传给yield,由yield赋值给food
        然后再往下执行,直到再次碰到yield,然后把yield后的返回值返回
    
  • 写个点菜的小程序:

        #这个地放是初试化的,
        def init(func):
            def wrapper(*args,**kwargs):
                res=func(*args,**kwargs) 
                res.__next__()
                return res
            return wrapper
        #开始点菜
        @init
        def cai_menu(*args,**kwargs):
            food_list=[]
            while True:
                food=yield
                food_list.append(food)
                print('你选择了%s ' % food_list)
    
        name=cai_menu()
        name.send(('脑袋','大腿'))   #send 必须用元组的方式来传值
    
匿名函数
        Lambda 函数也叫匿名函数,匿名就是没有名字,在我看来,如果你的函数只是临时一用,而且业务简单的话,就没必要
        去创建一个有名字的函数.
  • 一个小栗子:
        >>> lambda x,y:x+y
        <function <lambda> at 0x0000022D22563E18>
        前面的x,y是数值,冒号后面是返回值,明显在求和.但是没有名字如何使用呢,我们就给他绑定一个名字,
        这样就可以了
        >>> add = lambda x,y:x+y
        >>> add(2,3)
        5
    
map,filter,reduce
        上面说到了匿名函数,肯定少不了他们几个,算上lambda一共四个内置函数
  • map() 他可以接受两个参数,一个是函数,一个是序列
    例子:
    map(func,seq)
    >>> li=[1,2,3,4,5,]
    >>> add = map(lambda x,y:x+y,li)
    >>> print(add)

    >>> add = map(lambda x:x+2,li)
    >>> print(list(add)) ##这个也就是说返回的是个列表
    [3, 4, 5, 6, 7]

        map 会吧列表里的元素逐个循环,放到前面的函数中去.执行函数,返回一个内存地址.使用list()来得到值
    
  • filter 提供了一个优雅的方式来过滤函数,满足函数的要求才过滤出来
    filter(function, sequence):对sequence中的item依次执行function(item),将执行结果为True的item组成一个List/String/Tuple(取决于sequence的类型)
    filter(func,seq)

        li= [1,2,3,4,5]
        fil = filter(lambda x:x%2,li)
        >>> print(list(filter))
        [1, 3, 5]
    
  • reduce
    If seq = [ s1, s2, s3, … , sn ], calling reduce(func, seq) works like this:
    At first the first two elements of seq will be applied to func, i.e. func(s1,s2) The list on which reduce() works looks now like this: [ func(s1, s2), s3, … , sn ]
    In the next step func will be applied on the previous result and the third element of the list, i.e. func(func(s1, s2),s3)
    The list looks like this now: [ func(func(s1, s2),s3), … , sn ]
    Continue like this until just one element is left and return this element as the result of reduce()
    总的来说就是一个列表[s1,s2,s3,…sn].reduce函数会先把s1与s2拿出来进行计算,然后计算的结果在与s3进行.
    以此类推

            例子:
                li= [1,2,3,4,5]
                >>> from  functools  import reduce
                >>> add  =  reduce (lambda x,y:x+y,li)
                >>> print(add)
                15
                >>> 
            在上面的例子中,我导入了一个包,在3里面reduce给封装到这个函数里面了.
    
谈谈面向过程
        在linux中我们经常用grep -rl  关键字   目录  来搜寻东西.现在我们用python来实现

        import os
        def init(func):
            def wrapper(*args,**kwargs):
                res=func(*args,**kwargs)
                next(res)
                return res
            return wrapper

        @init
        def search(target):
            while True:
                search_path=yield
                g=os.walk(search_path)
                for par_dir,_,files in g:
                    for file in files:
                        file_abs_path=r'%s\%s' %(par_dir,file)
                        # print(file_abs_path)
                        target.send(file_abs_path)

        @init
        def opener(target):
            while True:
                file_abs_path=yield
                # print('opener func==>',file_abs_path)
                with open(file_abs_path,encoding='utf-8') as f:
                    target.send((file_abs_path,f))

        @init
        def cat(target):
            while True:
                file_abs_path,f=yield  #(file_abs_path,f)
                for line in f:
                    tag=target.send((file_abs_path,line))
                    if tag:
                        break
        @init
        def grep(target,pattern):
            tag=False
            while True:
                file_abs_path,line=yield tag
                tag=False
                if pattern in line:
                    tag=True
                    target.send(file_abs_path)

        @init
        def printer():
            while True:
                file_abs_path=yield
                print(file_abs_path)



        x=r'C:\Users\Administrator\PycharmProjects\python17期\day5\a'



        g=search(opener(cat(grep(printer(),'python'))))
        print(g)

        g.send(x)
        面向过程的程序设计:是一种流水线式的编程思路,是机械式
        优点:
            程序的结构清晰,可以把复杂的问题简单

        缺点:
            1 扩展性差


        应用场景:
            1 linux内核,git,httpd

模块与包

        导入模块: import xxxx
        或者:  from  xxx import    或者   from xxx import xxx as  xxx 这样无非也就是起个别名

        模块支持从逻辑上阻止python代码,挡代码量相当大的时候,我 们最好吧代码分成一些有组织的代码段.
        前提是他们要彼此交互,
        他们可能是一个累,可以是函数,这些代码是共享的.
        吧其他模块加入到你的模块中的操作叫导入(import) ,那些自慰包含并具有组织代码的代码片段是模块(moudle)
  • 一个Python Module(模块),是一个文件,包含了Python对象定义和Python语句(definitions and statements)。文件名就是模块名加上后缀.py,在模块内部,模块名存储在全局变量__name__中,是一个string,可以直接在module中通过__name__引用到module name。
    module是为了重复使用一些对象,比如类,函数,而将这些对象定义放在一个.py文件中,或是将一个较大的工程裁缝为多个.py文件而易于维护,每一个.py文件都是一个module。
    
posted @ 2017-06-03 16:47  隔壁家的二狗  阅读(249)  评论(0)    收藏  举报