您的位置:首页 > 其它

13lambda_yield_yieldfrom_coroutine

2019-05-03 13:57 302 查看

 

 

目录

匿名函数... 1

生成器generator:... 2

生成器函数:... 2

生成器应用:... 5

coroutine协程:... 6

 

 

 

匿名函数

 

匿名,即没有名字,没有名字的函数;

python借助lambda表达式构建匿名函数;

 

格式:

lambda 参数列表: 表达式

参数列表不需要小括号;

冒号是用来分割参数列表和表达式的;

不需要使用return,表达式的值就是匿名函数的返回值;

lambda表达式只能写在一行上,被称为单行函数;

用途,高阶函数传参时,使用lambda表达式,往往能简化代码;

 

例:

In [2]: lambda x: x**2

Out[2]: <function __main__.<lambda>>

In [3]: (lambda x: x**2)(4)   #调用

Out[3]: 16

In [4]: foo=lambda x,y:(x+y)**2   #不推荐这么用

In [5]: foo(2,1)

Out[5]: 9

In [6]: def foo(x,y):   #如果复杂时,建议使用普通函数

   ...:     return (x+y)**2

   ...: foo(2,1)

   ...:

Out[6]: 9

In [7]: lst=['a',2,1]

In [8]: lst.sort(key=str)   #高阶函数,str为函数

In [9]: lst

Out[9]: [1, 2, 'a']

In [10]: lambda :0   #无参函数,返回常数0

Out[10]: <function __main__.<lambda>>

In [11]: (lambda x,y=3:x+y)(5)

Out[11]: 8

In [12]: (lambda x,y=3: x+y)(5,6)

Out[12]: 11

In [13]: (lambda x,*,y=30: x+y)(5)

Out[13]: 35

In [14]: (lambda x,*,y=30: x+y)(5,y=10)

Out[14]: 15

In [15]: (lambda *args:(x for x in args))(*range(5))   #生成器,惰性求值

Out[15]: <generator object <lambda>.<locals>.<genexpr> at 0x7f892ccaca40>

In [16]: (lambda *args: [x for x in args])(*range(5))   #列表解析,立即求值

Out[16]: [0, 1, 2, 3, 4]

In [18]: (lambda *args: {x+2 for x in args})(*range(5))

Out[18]: {2, 3, 4, 5, 6}

In [20]: [x for x in (lambda *args: map(lambda x: x+1,args))(*range(5))]   #高阶函数

Out[20]: [1, 2, 3, 4, 5]

In [22]: [x for x in (lambda *args: map(lambda x: (x+1,args),args))(*range(5))]

Out[22]:

[(1, (0, 1, 2, 3, 4)),

 (2, (0, 1, 2, 3, 4)),

 (3, (0, 1, 2, 3, 4)),

 (4, (0, 1, 2, 3, 4)),

 (5, (0, 1, 2, 3, 4))]

 

 

 

生成器generator:

生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yield关键字得到一个生成器函数,调用这个函数得到一个生成器对象;

库函数中有大量使用;

生成器表达式和生成器函数能够生成生成器对象;

 

 

 

生成器函数:

函数中包含yield语句的函数,返回生成器对象;

生成器对象,是一个可迭代对象,是一个迭代器;

生成器对象,是延迟计算,惰性求值的;

普通的函数在调用后,会立即执行完毕,但生成器函数可使用next()多次执行;

生成器函数等价于生成器表达式,只不过生成器函数更加复杂;

生成器函数,核心:让出;

 

在生成器函数中,使用多个yield语句,执行一次后会暂停执行,把yield表达式的值返回;

再次执行会执行到下个yield语句;

return语句依然可以终止函数运行,但return语句的返回值不能被获取到,生成器函数中一般不加return语句;

return会导致无法继续获取下一个值,抛StopIteration异常;

如果函数没有显式的return语句,如果生成器函数执行到结尾一样会抛StopIteration异常;

 

包含yield语句的生成器函数,生成生成器对象时,生成器函数的函数体不会立即执行;

next(generator)会从函数的当前位置向后执行到之后碰到的第一个yield语句,会弹出值,并暂停函数执行,next()可理解为拨一下转一次;

再次调用next(),和上一条一样的处理过程,当没有元素时可给缺省值next(g,'End'),防止抛异常;

没有多余的yield语句能被执行,继续调用next(),会抛StopIteration异常;

 

例:

In [23]: def inc():

    ...:     for i in range(5):

    ...:         yield i   #出现yield就是生成器函数

    ...:        

In [24]: type(inc)

Out[24]: function

In [25]: type(inc())

Out[25]: generator

In [26]: x=inc()

In [27]: type(x)

Out[27]: generator

In [28]: next(x)

Out[28]: 0

In [29]: for n in x:

    ...:     print(n)

    ...:    

1

2

3

4

In [30]: for n in x:

    ...:     print(n)   #x在上个for中已迭代完

    ...:    

    ...:    

In [39]: y=(i for i in range(2))

In [40]: type(y)

Out[40]: generator

In [41]: next(y)

Out[41]: 0

In [42]: next(y)

Out[42]: 1

In [43]: next(y)

---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

<ipython-input-43-81b9d2f0f16a> in <module>()

----> 1 next(y)

StopIteration:

 

例:

In [44]: def gen():

    ...:     print('line1')

    ...:     yield 1

    ...:     print('line2')

    ...:     yield 2

    ...:     print('line3')

    ...:     return 3

    ...:

In [45]: next(gen())

line1

Out[45]: 1

In [46]: next(gen())

line1

Out[46]: 1

In [47]: g=gen()

In [48]: next(g)

line1

Out[48]: 1

In [49]: next(g)

line2

Out[49]: 2

In [50]: next(g)

line3

---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

<ipython-input-50-e734f8aca5ac> in <module>()

----> 1 next(g)

StopIteration: 3

In [51]: g=gen()

In [52]: next(g)

line1

Out[52]: 1

In [53]: next(g)

line2

Out[53]: 2

In [54]: next(g,'End')   #没有元素,给缺省值

line3

Out[54]: 'End'

In [55]: next(g,'End')

Out[55]: 'End'

 

无限循环:

例:

def counter():
    i = 0
    while True:
        i += 1
        yield i

def inc(c):
        return next(c)

c = counter()
print(inc(c))
print(inc(c))
print(inc(c))

##############

def counter2():
    i = 0
    while True:
        i += 1
        yield i

def inc2():
    c = counter()
    return next(c)

print(inc2())   #1
print(inc2())   #1
print(inc2())   #1,每次都创建生成器对象

 

 

生成器应用:

计数器:

def inc():
    def counter():
        i = 0
        while True:
            i += 1
            yield i
    c = counter()
    return lambda : next(c)   #相当于如下三行,闭包,用到了外层函数的自由变量c,lambda表达式是匿名函数,return返回的是一个匿名函数
    #def _inc():
        #return next(c)
    #return _inc
foo = inc()
print(foo())
print(foo())

 

处理递归问题:

def fib():
    x = 0
    y = 1
    while True:
        yield y
        x,y = y,x+y

foo=fib()
for i in range(5):
    print(next(foo))

for _ in range(100):
    print(next(foo))
#print(next(foo))

 

 

 

coroutine协程:

生成器的高级用法;

比进程、线程轻量级;

是在用户空间调度函数的一种实现;

 

python3 asyncio就是协程实现,已加入到标准库;

python3.5使用async、await关键字直接原生支持协程;

 

协程调度器实现思路,有2个生成器A、B,next(A)后,A执行到了yield语句暂停,然后去执行next(B),B执行到yield语句也暂停,然后再次调用next(A),再调用next(B),周而复始,就实现了调度效果;可引入调度的策略来实现切换的方式;

协程是一种非抢占式调度;

 

yield from语句:

python3.3出现的新语法;

yield from iterrable是for item in iterable: yield item形式的语法糖,从可迭代对象中一个个拿元素;

 

例:

In [56]: def inc():

    ...:     for x in range(1000):

    ...:         yield x

    ...:        

In [57]: def inc():

    ...:     yield from range(1000)

    ...:    

In [58]: foo=inc()

In [59]: next(foo)

Out[59]: 0

In [60]: next(foo)

Out[60]: 1

 

例:

In [68]: def counter(n):

    ...:     yield from range(n)

    ...:    

In [69]: def inc(n):

    ...:     yield from counter(n)

    ...:    

In [70]: foo=inc(10)

In [71]: next(foo)

Out[71]: 0

In [72]: next(foo)

Out[72]: 1

 

习题:

1、把一个字典扁平化flat;

源字典:{'a':{'b':1,'c':2},'d':{'e':3,'f':{'g':4}}}

 

2、实现base64编码,要求自己实现算法;

3个8bit字节3*8-->转化为4个6bit字节4*6,之后在6bit的前面补两0,形成8bit一个字节的形式,如果剩下的字符不是3个字节,则用0填充,输出字符使用=,因此编码后输出的文本末尾可能会出现1个或2个=;

编码大小为2**6=64;

每一段当作一个8bit看它的值,这个值就是base64编码表的索引值,找到对应字符,再取3个字节,同样处理,直到最后;

例:

abc对应的ascii为:0x61,0x62,0x63,十进制为97,98,99

01100001 01100010 01100011

011000 010110 001001 100011

00011000 00010110 00001001 00100011

24 22 9 35

末尾处理:

正好3个字节,处理方法同上;

剩1个字节或2个字节,用0补满3个字节;

补0的字节用=表示;

大小端模式:

大端模式(Big-endian),是指数据的高字节,保存在内存的低地址中,而数据的低字节,保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;

小端模式(Little-endian),是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致;

在C语言中,默认是小端(但在一些对于单片机的实现中却是基于大端,比如Keil 51C),Java是平台无关的,默认是大端;在网络上传输数据普遍采用的都是大端;

In [48]: b=int.from_bytes('abc'.encode(),'big')

In [49]: b

Out[49]: 6382179

In [50]: hex(b)

Out[50]: '0x616263'

In [52]: b=int.from_bytes('abc'.encode(),'little')

In [53]: hex(b)

Out[53]: '0x636261'

In [54]: type(b)

Out[54]: int

In [55]: import base64

In [56]: base64.b64encode('abc'.encode())

Out[56]: b'YWJj'

i18n(其来源是英文单词internationalization的首末字符i和n,18为中间的字符数)是“国际化”的简称。在资讯领域,国际化(i18n)指让产品(出版物,软件,硬件等)无需做大的改变就能够适应不同的语言和地区的需要。对程序来说,在不修改内部代码的情况下,能根据不同语言及地区显示相应的界面。在全球化的时代,国际化尤为重要,因为产品的潜在用户可能来自世界的各个角落。通常与i18n相关的还有L10n(“本地化”的简称)。

 

3、求2个字符串的最长公共子串;

 

1、

src = {'a':{'b':1,'c':2},'d':{'e':3,'f':{'g':4}}}

target = {}

 

def flatmap(src,prefix=''):

    for k,v in src.items():

        if isinstance(v,(dict)):

            flatmap(v,prefix=prefix+k+'.')

        else:

            target[prefix+k] = v

 

flatmap(src)

print(target)

#####################

src = {'a':{'b':1,'c':2},'d':{'e':3,'f':{'g':4}}}

 

def flatmap(src,dst=None,prefix=''):

    if dst == None:  

        dst = {}

    for k,v in src.items():

        if isinstance(v,(dict)):

            flatmap(v,dst,prefix=prefix+k+'.')   #recursion调用

        else:

            dst[prefix+k] = v

    return dst

 

flatmap(src)

注:

用户输入的判断,这些代码通常比业务逻辑代码长好几倍,健壮的代码无论怎么运行都不会意外崩溃;

一般不说明的情况下,都不会改源数据(源列表、源字典等);

能否不暴露给外界内部的dst;

能否函数就提供一个参数源字典,返回一个新的扁平化字典;

递归时要把目标字典的引用传递多层,如何处理;

########################

src = {'a':{'b':1,'c':2},'d':{'e':3,'f':{'g':4}}}

 

def flatmap(src):

    def _flatmap(src,dst,prefix=''):

        for k,v in src.items():

            if isinstance(v,(dict)):

                _flatmap(v,dst,prefix=prefix+k+'.')

            else:

                dst[prefix+k] = v

    dst = {}

    _flatmap(src,dst)

    return dst

 

flatmap(src)

注:

不关心_flatmap函数内部如何实现,如内部用的数据结构、临时对象、算法等,只关心调用后返回的结果;

#######################

src = {'a':{'b':1,'c':2},'d':{'e':3,'f':{'g':4}}}

 

def flatmap(src):

    def _flatmap(src,dst,prefix=''):

        for k,v in src.items():

            key = prefix + k

            if isinstance(v,(dict)):

                _flatmap(v,dst,key+'.')

            else:

                dst[key] = v

    dst = {}

    _flatmap(src,dst)

    return dst

 

flatmap(src)

 

2、

import string

import base64

 

alphabet = b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

#teststr = 'abcd'

# teststr = 'abc'

teststr = 'ManMa'

 

def base(src):

    ret = bytearray()

    length = len(src)

    r = 0

    for offset in range(0,length,3):

        if offset + 3 <= length:

            triple = src[offset:offset+3]

        else:

            triple = src[offset:]

            r = 3 - len(triple)

            triple = triple + '\x00' * r

        #print(triple,r)

        b = int.from_bytes(triple.encode(),'big')

        #print(hex(b))

        for i in range(18,-1,-6):

            if i == 18:

                index = b >> i

            else:

                index = b >> i & 0x3F

            ret.append(alphabet[index])

        for i in range(1,r+1):

            ret[-i] = 0x3D

    return bytes(ret)

 

print(base(teststr))

print('*' * 50)

print(base64.b64encode(teststr.encode()))

注:

alphabet = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/'

 

3、

def findit(str1,str2):

    length = len(str1)

    for sublen in range(length,0,-1):

        for start in range(0,length-sublen+1):

            substr = str1[start:start+sublen]

            if str2.find(substr) != -1:

                print('substrlen={}'.format(substr))

                return substr

 

s1 = 'abcd'

s2 = 'abcefgd'

s3 = '123a'

print(findit(s1,s2))   #传参时要注意,str1为短字串,str2为长字串

print(findit(s1,s3))

 

 

 


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: