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))
  • 相关阅读:
    prototype.js超强的javascript类库
    MySQL Server Architecture
    Know more about RBA redo block address
    MySQL无处不在
    利用Oracle Enterprise Manager Cloud Control 12c创建DataGuard Standby
    LAMP Stack
    9i中DG remote archive可能导致Primary Database挂起
    Oracle数据库升级与补丁
    Oracle为何会发生归档日志archivelog大小远小于联机重做日志online redo log size的情况?
    Oracle Ksplice如何工作?How does Ksplice work?
  • 原文地址:https://www.cnblogs.com/shawnhuang/p/10214120.html
Copyright © 2011-2022 走看看