zoukankan      html  css  js  c++  java
  • 函数进阶三(生成器、生成器表达式、匿名函数)

    . 昨日内容回顾
    函数名的运用:
    1.特殊的变量
    2.函数名可以当作变量赋值
    3.函数名可以当作容器类类型的元素
    4.函数名可以当作函数的参数
    5.函数名可以当作函数的返回值

    闭包:
    1.内层函数对外层函数(非全局)变量的引用和改变
    2.闭包只存在于内层函数中
    3.闭包都要逐层返回,最终返回给最外层函数

    闭包的特点:
    解释器遇到闭包,不会随着函数的结束而结束空间

    闭包应用:
    装饰器
    爬虫

    可迭代对象
    判断方法:
    obj
    "__iter__" in dir(obj)

    from collections import Iterable
    isinstance(obj, Iterable)

    可迭代对象不能直接取值,必须转化成迭代器取值(__next__)

    # 迭代器
    "__iter__" in dir(obj)

    from collections import Iterable
    isinstance(obj, Iterator)

    while循环模拟for循环

    . 生成器

    生成器的本质就是迭代器,生成器是自己用Python代码写的迭代器
    生成器函数
    生成器表达式

    s1 = "ajlsdj"
    iter(s1) # 这不是手写,是通过Python写的

    将一个函数变成生成器函数
    只要有 yield 就不是函数,可看成生成器
    
    
    # 生成器函数
    
    def func():
        print(111)
        print(222)
        yield 666
        # yield "aklsj"
    
    # print(func())  # <generator object func at 0x000001AE6CB50BF8>  返回的是生成器对象
    ret = func()
    print(next(ret))  # 这里一个 next 对应一个 yield
    # print(next(ret))  # 所以这里会报错 StopIteration,除非上面再加个 yield
    # 111
    # 222
    # 666
    
    
    
    # yield 和 return 的共同点和区别
    
    # 1. 区别:return 终止函数,而 yield 不会终止生成器函数
    # 2. 共同点:都会返回一个值,return给函数的执行者返回值,yield是给next()返回值
    
    # 示例:
    def cloth():
        for i in range(1, 5001):
            print("我写的代码没有bug 衣服%s号" % i)
    cloth()
    
    # 我写的代码没有bug 衣服1号
    # 我写的代码没有bug 衣服2号
    # 。。。
    # 我写的代码没有bug 衣服5000号
    
    def cloth1():
        for i in range(1, 5001):
            yield "有志青年 衣服%s号" % i
    
    genor = cloth1()
    
    for i in range(1, 101):
        print(next(genor))
    
    for i in range(1, 51):
        print(next(genor))
    
    # 有志青年 衣服1号
    # 有志青年 衣服2号
    # 。。。
    # 有志青年 衣服100号
    # 有志青年 衣服101号
    # 。。。
    # 有志青年 衣服149号
    # 有志青年 衣服150号
    
    # 由打印结果可知,生成器会记录上一次运行的位置,再次运行时从上一次位置开始计数
    # 以下很重要,必须掌握
    # send next
    
    def func():
        yield 666
        yield "abc"
        yield "速度"
        yield "hxy"
    genor = func()
    print(next(genor)) # 666
    print(next(genor)) # abc
    
    print(genor.send(None)) # send() 必须要有一个参数  # 666
    print(genor.send(None)) # abc
    
    # send 不仅能对应 yield 取值,而且可以给上一个 yield 发送一个值
    # 注意前提是上一个 yield 必须赋值给一个变量,否则不会打印 send给它发送的值
    def func(): count = yield 666 print(count) s = yield "abc" print(s) yield "速度" yield "hxy" genor = func() print(genor.send(None)) # 666 print(genor.send("alex")) # alex abc print(genor.send("111")) # 111 速度 # 第一个取值能否用 send 传参? # 不能,比如上面的 print(genor.send(None)) 中的 None 改为 其他的,那么会报错 # 因为 send 是给上一个 yield 发送一个值,第一个上面没有值了 # 最后一个 yield 永远也得不到 send 传的值。
    # yield from 将一个可迭代对象变成一个迭代器返回
    
    def func():
        lst = ["abc", "def", "ghi", "jkl"]
        yield lst
    genor = func()
    print(next(genor))  # ['abc', 'def', 'ghi', 'jkl']
    for i in genor:
        print(i)
        
    # ['abc', 'def', 'ghi', 'jkl']
    
    def func():
        lst = ["abc", "def", "ghi", "jkl"]
        yield from lst  # 注意这里与上面的区别
    genor = func()
    print(next(genor))  # abc
    print(next(genor))  # def
    print(next(genor))  # ghi
    print(next(genor))  # jkl
    for i in genor:
        print(i)
    # abc
    # def
    # ghi
    # jkl
    . 列表推导式,生成器表达式
    列表推导式——用一行代码构建一个简单或较复杂的列表
    好处:减少代码量

    li = [i for i in range(1, 101)]
    print(li)
    # 列表推导式分三种情况:
    
    # 1. 循环模式——[变量(加工后的变量) for 变量 in iterable]
    
    # 构建一个列表:['python1期', 'python2期', ...'python25期']
    print(["python%i期" % i for i in range(1, 26)])
    
    # 2. 筛选模式——[变量(加工后的变量) for 变量 in iterable if 条件]
    
    # 30以内所有的偶数(两种方法)
    print([i for i in range(2, 31, 2)])
    print([i for i in range(1, 31) if i % 2 == 0])
    
    # 其他示例
    print([i for i in range(1, 31) if i % 3 == 0])
    print([i**2 for i in range(1, 31) if i % 3 == 0])
    print(["地球%s号" % i for i in range(1, 100, 2)])
    
    # 3. 三元模式——循环模式的变异
    # 个人认为如果要用到 if...else...结构的话就以三元模式把 if...else...写在前面,如果只有一个 if 就用筛选模式把 if 放到后面
    # 构建一个列表,里面的元素是1-20,能被3整除的元素要替换成*
    # print("*" if 3 > 2 else 1)
    print(["*" if i % 3 == 0 else i for i in range(1, 21)])
    
    # 将至少含有两个e的名字放到一个列表
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    # 方法一
    l = []
    for i in names:
        for j in i:
            if j.count("e") >= 2:
                l.append(j)
    print(l)
    
    # 方法二
    print([j for i in names for j in i if j.count("e") >= 2])
    
    # 列表推导式总结:
    # 优点:一行搞定,节省代码行数
    # 缺点:不能用debug模式,列表推导式相对复杂的列表不能用,三层以上效率低也很难写
    # 生成器表达式
    # 它与列表推导式写法几乎一样,也有同样的三种模式,只需将[]换成()就可以
    
    # 列表推导式
    print(["python%i期" % i for i in range(1, 26)])
    
    # 生成器表达式
    ret = ("python%i期" % i for i in range(1, 26))
    for i in ret:
        print(i)
    
    # 元组没有推导式!!!因为上面的生成器表达式已经用()来表示了
    
    # 字典推导式
    
    print({i:None for i in range(1, 10)})
    # {1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None}
    
    # 将下面字典的键值对调
    mcase = {"a": 10, "b": 34, "c":20, "d":15}
    print({v:k for k,v in mcase.items()})
    
    # 集合推导式
    
    # 将{1, -2, 3, -4, 4}的所有元素取平方
    set1 = {1, -2, 3, -4, 4}
    print({i**2 for i in set1})
    # {16, 1, 4, 9}  顺便去重了
    # 四. 匿名函数lambda
    
    def func(x, y):
        return x + y
    print(func(3, 4))
    
    # 像上面这种只有return 即返回值的函数,可以使用匿名函数 lambda
    # 匿名函数只能用一行代码表示,冒号前面是参数,后面是返回值
    
    func2 = lambda x,y: x + y  # func2就是这个匿名函数的名字
    print(func2(3, 4))
    
    # 写一个匿名函数,需要三个数字参数,返回值为三个数想乘的结果
    func3 = lambda a, b, c: a * b * c
    print(func3(1, 2, 3))
  • 相关阅读:
    EnterpriseLibrary
    如何只保证窗口只打开一次[即只运行一个进程]
    设计模式之工厂方法模式
    设计模式之代理类
    asp.net mvc应用架构的思考--Unity的应用及三层代码
    为什么我说不要用TransactionScope
    Redis入门学习
    实战分层架构
    asp.net mvc 4多级area实现技巧
    jsonp其实很简单【ajax跨域请求】
  • 原文地址:https://www.cnblogs.com/shawnhuang/p/10214120.html
Copyright © 2011-2022 走看看