Python 函数进阶2

一、协程函数与yield

协程,又称微线程,纤程。英文名Coroutine。

用法:

def eater(name):
    print('%s 说:我买了好多东西:' %name)
    food_list=[]
    while True:
        food=yield food_list
        food_list.append(food) #['香蕉','苹果']
        print('%s 最爱吃的 %s' %(name,food))
name_g=eater('翔子')

 

#第一阶段:初始化
next(name_g) #等同于name_g.send(None)
#第二阶段:给yield传值
print(name_g.send('香蕉')) #1 先给当前暂停位置的yield传骨头 2 继续往下执行,直到再次碰到yield,然后暂停并且把yield后的返回值当做本次调用的返回值
print(name_g.send('苹果'))
print(name_g.send('梨'))

1、把函数的执行结果封装好__iter__和__next__,即得到一个迭代器
2、与return功能类似,都可以返回值,但不同的是,return只能返回一次值,而yield可以返回多次值;
3、函数暂停与再继续运行的状态是有yield保存

解决初始化问题,使用装饰器

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 最爱吃的 %s' %(name,food))
name_g=eater('翔子')
#第二阶段:给yield传值
print(name_g.send('香蕉'))

1、先给当前暂停位置的yield传香蕉;
2、继续往下执行,直到再次碰到yield,然后暂停并且把yield后的返回值当做本次调用的返回值;

二、递归函数

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。

#直接调用
def func():
    print('from func')
    func()
func()

#间接调用
def foo():
    print('from foo')
    bar()
def bar():
    print('from bar')
    foo()
foo()

举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示,可以看出:

fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n

所以,fact(n)可以表示为n x fact(n-1),只有n=1时需要特殊处理。

于是,fact(n)用递归的方式写出来就是:

def fact(n):
    if n==1:
        return 1
    return n * fact(n - 1)

上面就是一个递归函数。可以试试:

>>> fact(1)
1
>>> fact(5)
120

如果我们计算fact(5),可以根据函数定义看到计算过程如下:

===> fact(5)

===> 5 * fact(4)

===> 5 * (4 * fact(3))

===> 5 * (4 * (3 * fact(2)))

===> 5 * (4 * (3 * (2 * fact(1))))

===> 5 * (4 * (3 * (2 * 1)))

===> 5 * (4 * (3 * 2))

===> 5 * (4 * 6)

===> 5 * 24

===> 120

递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。

总结:

1、使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。

2、针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。

3、Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。

三、二分法

二分法是一种快速查找的方法,时间复杂度低,逻辑简单易懂,总的来说就是不断的除以2除以2...

例:

l = [1,2,5,7,10,31,44,47,56,99,102,130,240]  查找32 是否在其中

1.如果找到该值就返回

2.如果找不到该值就返回该值的上一个Index和下一个Index

3.小于List[0] 返回0

4.大于len(List)返回该List[-1]

def binary_search(l,num):
    print(l) #[10, 31]
    if len(l) > 1:
        mid_index=len(l)//2 #1
        if num > l[mid_index]:
            #in the right
            l=l[mid_index:] #l=[31]
            binary_search(l,num)
        elif num < l[mid_index]:
            #in the left
            l=l[:mid_index]
            binary_search(l,num)
        else:
            print('find it')
    else:
        if l[0] == num:
            print('find it')
        else:
            print('not exist')
        return
    binary_search(l,32)

执行结果:

[1, 2, 5, 7, 10, 31, 44, 47, 56, 99, 102, 130, 240]
[1, 2, 5, 7, 10, 31]
[7, 10, 31]
[10, 31]
[31]
not exist
posted on 2017-08-04 11:17  wangyinhu1208  阅读(174)  评论(0编辑  收藏  举报