• 闭包、装饰器、迭代器、生成器


    一、闭包:
    1,闭包存在于函数中。
    2,闭包就是内层函数对外层函数(非全局变量)的引用。
    3,最内层函数名会被逐层的返回直至返回给最外层。

    def func():
        name = 'alex'
        def inner():
            print(name)
        return inner	
    ret = func()  # inner
    # ret()
    print(ret.__closure__)  # 只要返回cell 它就是闭包
    print(ret.__closure__[0])# 只要返回cell 它就是闭包
    print(ret.__closure__[0].cell_contents)  # 只要返回cell 它就是闭包
    
    
    name = 'barry'
    def func():
        def inner():
            print(name)
        return inner
    ret = func()  # inner
    # ret()
    print(ret.__closure__)  # 只要返回None它就不是闭包
    
    
    #不是闭包
    name = 1
    def func():
        print(name)
    func()
    
    
    #是闭包 n1虽然是外部全局变量,但当时传参数时  name = n1 ,那就是相当于外层函数有个name的变量
    def func(name):
        def inner():
            print(name)
        return inner
    n1 = 'barry'
    ret = func(n1)  # inner
    print(ret.__closure__)
    

      

    # 闭包的作用是什么?
    
    def func(step):
        num = 1
        num += step
        print(num)
    
    for i in range(5):
        func(2)
    
    # 闭包的作用:解释器遇到闭包,会触发一个机制,这个闭包不会随着它的结束而释放。
    def func(step):
        num = 1
        def inner():
            nonlocal num
            num += step
            print(num)
        return inner
    
    f = func(2)
    for i in range(5):
        f()
    f()
    f()
    

      


    闭包的应用(网页爬取)

    from urllib.request import urlopen
    def func():
        content = urlopen("http://www.cnblogs.com/jin-xin/articles/8259929.html").read()
        return content
    
    #print(func())
    print(func().decode('utf-8'))
    
    
    from urllib.request import urlopen
    def but(a):
        content = urlopen(a).read()
        def get_content():
            return content
        return get_content
    fn = but('http://www.cnblogs.com/jin-xin/articles/8259929.html')
    #fn = but('http://www.cnblogs.com/jin-xin/articles/8254334.html')
    con = fn()   # 获取内容 
    print(con.decode('utf-8'))
    print(con.decode('utf-8'))
    print(con.decode('utf-8'))
    print(con.decode('utf-8'))   #中文显示
    content2 = fn()  # 重新获取内容
    print(content2.decode('utf-8'))
    

      

    二、装饰器
    其实装饰器本质是闭包,在不改变原函数的调用指令情况下,给原函数增加额外的功能。它的传参,返回值都是借助内层函数inner,
    它之所以借助内层函数inner 就是为了让被装饰函数 在装饰器装饰前后,没有任何区别,看起来没有变化。

    进化序列:

    # 第一版:写一个功能测试其他同事的函数的执行效率
    import time
    
    def func():
        time.sleep(0.2)
        print('非常复杂')
    
    def func1():
        time.sleep(0.3)
        print('超级复杂')
    
    start_time = time.time()
    func()
    end_time = time.time()
    print('此函数的执行效率为%s' % (end_time - start_time))
    
    
    # 第二版:
    import time
    
    def func():
        time.sleep(0.2)
        print('非常复杂')
    
    def func1():
        time.sleep(0.3)
        print('超级复杂')
    
    def timmer(f):
        start_time = time.time()
        f()
        end_time = time.time()
        print('此函数的执行效率为%s' % (end_time - start_time))
    
    timmer(func)
    timmer(func1)
    # func()
    # 如果在实际项目中测试函数,
    # 假如函数有1500个,那么你1500个timmer(func),工作量很大。
    # 你要在不改变函数执行的指令下,同时测试效率。
    
    
    
    # 第三版:在不改变函数的执行方式下,同时测试执行效率。
    # 装饰器的雏形
    import time
    
    def func():
        time.sleep(0.2)
        print('非常复杂')
    
    def func1():
        time.sleep(0.3)
        print('超级复杂')
    
    def timmer(f):
        def inner():
            start_time = time.time()
            f()
            end_time = time.time()
            print('此函数的执行效率为%s' % (end_time - start_time))
        return inner
    
    func = timmer(func)
    # 语法糖 @
    func()
    func1 = timmer(func1)
    func1()
    
    
    
    # 装饰器的雏形的优化
    # timmer 就是装饰器: 在不改变原函数的调用指令情况下,给原函数增加额外的功能。
    import time
    
    def timmer(f):
        def inner():
            start_time = time.time()
            f()
            end_time = time.time()
            print('此函数的执行效率为%s' % (end_time - start_time))
        return inner
    
    @timmer # func = timmer(func)
    def func():
        time.sleep(0.2)
        print('非常复杂')
    
    @timmer # func1 = timmer(func1)
    def func1():
        time.sleep(0.3)
        print('超级复杂')
    
    func()
    func1()
    
    # 被装饰函数带参数
    import time
    
    def timmer(f):
        def inner(*args,**kwargs):  # 函数的定义: * 聚合。args = (1,2,3,434545,4234.)
            # a1 = 'wusir'
            # b1 = 'alex'
            start_time = time.time()
            f(*args,**kwargs)  # 函数执行:* 打散。f(*(1,2,3,434545,4234.),)
            end_time = time.time()
            print('此函数的执行效率为%s' % (end_time - start_time))
        return inner
    
    @timmer # func = timmer(func)
    def func(a,b):
        time.sleep(0.2)
        print('非常复杂%s%s'% (a,b))
    func('wusir','alex')  # inner()
    
    @timmer # func = timmer(func)
    def func(a,b,c):
        time.sleep(0.2)
        print('非常复杂%s%s%s'% (a,b,c))
    func('wusir','alex','barry')  # inner()
    
    # 被装饰的函数要有返回值
    import time
    
    def timmer(f):  # f = func
        def inner(*args,**kwargs):
            start_time = time.time()
            ret = f(*args,**kwargs)  # func()
            end_time = time.time()
            print('此函数的执行效率为%s' % (end_time - start_time))
            return ret
        return inner
    
    @timmer # func = timmer(func)
    def func(a,b):
        time.sleep(0.2)
        print('非常复杂%s%s'% (a,b))
        return 666
    ret = func('wusir','alex')  # inner()
    print(ret)
    
    @timmer # func = timmer(func)
    def func(a,b,c):
        time.sleep(0.2)
        print('非常复杂%s%s%s'% (a,b,c))
    func('wusir','alex','barry')  # inner()
    
    
    # 装饰器的应用
    flag = False
    
    def login():
        username = input('用户名')
        password = input('密码')
        if username == 'alex' and password == '123':
            print('登陆成功')
            global flag
            flag = True
    
    def auth(f): # f = func3函数名
        def inner(*args,**kwargs):
            while 1:
                if flag:
                    ret = f(*args,**kwargs)
                    return ret
                else:
                    login()
        return inner
    
    @auth
    def comment():
        print('欢迎来到评论页面')
    
    @auth
    def artcle():
        print('欢迎来到文章页面')
    
    @auth
    def dairy():
        print('欢迎来到日记页面')
    
    comment()
    artcle()
    dairy()
    
    dic = {
        1: artcle,
        2:dairy,
        3:comment,
    }
    

    三、迭代器


    可迭代对象:这个对象由多个元素组成,它就是可迭代的。
    这个对象内部只要含有"__iter__"方法,它就是可迭代的。
    遵循可迭代协议。可迭代对象不一定是迭代器,但迭代器一定是可迭代对象。

    # int str bool list tuple dict set bytes range 文件句柄
    不可以迭代对象:int bool
    可以迭代对象:str list tuple dict set bytes range 文件句柄

    判断一个对象是否是可迭代的 --> 是否含有"__iter__"方法
    s1 = 'alex'
    print(dir(s1))
    i = 100
    print(dir(i))
    print('__iter__' in dir(range))
    方法一:内部含有__iter__方法并且含有__next__方法的就是迭代器。
    l1 = [1,2,3]
    print('__iter__' in dir(l1)) #True
    print('__next__' in dir(l1)) #False
    
    
    
    
    方法二:判断一个对象是否是迭代器,可迭代对象的另一种方式:
    
    from collections.abc import Iterator
    from collections.abc import Iterable
    #from collections import Iterator #DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
    #from collections import Iterable #DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
    
    #列表
    l1 = [1,2,3,4]
    print(isinstance(l1,Iterator)) #False
    print(isinstance(l1,Iterable)) #True
    
    # 文件句柄?
    with open('test.py',encoding='utf-8') as f1:
        print(isinstance(f1,Iterator)) #True
    
    #可迭代对象不能直接取值,必须转化成迭代器进行取值。
    eg:
    l1 = [1,2,3] # 将一个可迭代对象 转化成迭代器
    for i in l1:
      print(i)
    
    l1 = [1, 2, 3] # 将一个可迭代对象 转化成迭代器
    obj1 = iter(l1)
    print(obj1)       #<list_iterator object at 0x000001E7EB8A2CF8>
    print(next(obj1)) # 一个next对应一个值
    print(next(obj1))
    print(next(obj1))
    判断一个对象是否是迭代器
    # while 模拟for循环循环可迭代对象的机制。
    # 1,将可迭代对象转化成迭代器。
    # 2,利用next进行取值。
    # 3,利用异常处理停止循环。
    l1 = [1, 2, 2, 3, 4, 4, 5, 5]
    # obj = l1.__iter__()
    obj = iter(l1)
    while 1:
        try:
            print(next(obj))
        except StopIteration:
            break

    迭代器有什么作用?
    1,节省内存。
    2,一条路走到底,不反复。
    3,不易看出。

      

      

    四、生成器

    生成器:本质就是迭代器,自己可以通过代码写出来的迭代器。
    生成器的生成方式:1.函数式生成器。2.生成器表达式。

    1、函数中只要有yield 它就不是函数了,它是生成器函数
    yield 与 return的区别:
    return直接终止函数,yield不会终止函数。
    return给函数的执行者返回值,yield是给next(生成器对象)返回值。

    def func():
        yield 5
        yield 6
        yield 7
        yield 8
    g = func() # 生成器对象
    print(g)
    # 一个next对应一个 yield
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    
    
    
    def book():
        for i in range(1,501):
            print('python全栈开发  编号%s' %i)
    
    def book_niu():
        for i in range(1,501):
            yield 'python全栈开发  编号%s' %i
    
    book()
    gen = book_niu()
    for i in range(50):
        print(next(gen))
    for i in range(30):
        print(next(gen))


    send方法
    send 与 next的区别 send不仅可以取值,还可以给上一个yield发送一个值
    第一个send不可以传值只能传None,因为上面无yield可传,最后一个yield 永远不会收到send发送的值

    def func():
        a = 1
        b = 2
        c = 3
        count = yield a + b + c
        print(count)
        yield 6
        yield 7
        yield 8
    g = func()
    print(next(g))
    print(g.send('barry'))  send不仅可以取值,还可以给上一个yield(例如:yield a + b + c)发送一个值
    print(g.send(None))
    print(g.send(None))
    

      

    yield from方法

    def func():
        l1 = ['barry', 'alex', 'wusir', '日天']
        # yield l1
        yield from l1  # 将一个可迭代对象转化成了生成器返回
    g = func()
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    # print(next(g))
    for i in g:
        print(i)
    

      



    2、生成器表达式与列表推导式 生成器表达式与列表推导式非常类似,容易着魔

     列表推导式:构建一个列表
    # [100以内所有的偶数],[0,2,4,6,8....100]

    l1 = []
    for i in range(0,101,2):
        l1.append(i)
    print(l1)
    
    # 列表推导式分为两种模式:
    # 用一行代码构建一个列表,列表推导式只能构建简单的或者比较复杂的列表。
    # 1,循环模式。 [变量(加工后的变量) for 变量 in iterable]
    print([i for i in range(0,101,2)])
    [1,4,9,16,25,36,49]
    print([i*i for i in range(1,8)])
    # ['python1期', 'python2期', .....'python20期']
    print(['python%s期'%i for i in range(1,21)])
    
    # 2,筛选模式
    # [变量(加工后的变量) for 变量 in iterable if 条件]
    print([i for i in range(1,31) if i % 3 == 0])
    # 30以内能被2整除的数的平方
    print([ i*i for i in range(1,31) if i % 2 == 0])
    # [1,2,3,4,6,7,8]
    print([i for i in range(1,9)if i != 5])
    l1 = ['wusir','ba', 'aa' ,'alex']
    # 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
    print([i.upper() for i in l1 if len(i) > 3])
    ['WUSIR','ALEX']
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    # 将列表中的至少含有两个'e'的人名留下来。
    # l1 = []
    # for l in names:
    #     for name in l:
    #         if name.count('e') >= 2:
    #             l1.append(name)
    # print(l1)
    print([name for l in names for name in l if name.count('e') >= 2])

      

      


    生成器表达式:生成器表达式和列表推导式的语法上一模一样,只是把[]换成()就行了。比如将十以内所有数的平方放到一个生成器表达式中

    生成器表达式和列表推导式的区别:

    列表推导式比较耗内存,所有数据一次性加载到内存。而.生成器表达式遵循迭代器协议,逐个产生元素。
    得到的值不一样,列表推导式得到的是一个列表.生成器表达式获取的是一个生成器
    列表推导式一目了然,生成器表达式只是一个内存地址。 无论是生成器表达式,还是列表推导式,他只是Python给你提供了一个相对简单的构造方式,因为使用推导式非常简单,所以大多数都会为之着迷,这个一定要深重,推导式只能构建相对复杂的并且有规律的对象,对于没有什么规律,而且嵌套层数比较多(for循环超过三层)这样就不建议大家用推导式构建。
    生成器的惰性机制: 生成器只有在访问的时候才取值,说白了.你找他要才给你值.不找他要.他是不会执行的.

    # print((i for i in range(1,31) if i % 3 == 0))
    gen = (i for i in range(1,31) if i % 3 == 0)
    for i in gen:
        print(i)
    

      

    # 匿名函数: 一句话函数
    # def func(a,b):
    #     return a + b
    # print(func(1,3))
    # func1 = lambda x,y: x + y
    # # print(func1(1,3))
    # print(func1)
    # 将 x, y 较大者返回
    # func2 = lambda x,y: x if x > y else y
    # print(func2(100,200))
    
    
    # eval 慎用
    # print('1 + 2')
    # print(eval('1 + 2'))
    
    # n=81
    # print(eval("n + 4"))  # 85
    #
    # exec
    # s1 = '''
    # for i in range(4):
    #     print(i)
    # '''
    # exec(s1)
    
    #
    # print(1,2,3,sep='|')  # 分隔符
    # print(1,2,3,end=' ')  # 换行符
    # f = open('log','w',encoding='utf-8')
    # print('写入文件',file=f,flush=True)
    # print(help(str))
    
    # def func():
    #     pass
    # ret = 888
    # # print(callable(func))
    # print(callable(ret))
    
    # print(float(100),type(float(100)))
    # print(bin(100))
    # print(abs(-100))
    #
    # ret = divmod(10,3)
    # print(ret)  # (商,余数)
    
    
    # sum  ***
    # print(sum([i for i in range(101)]))
    # print(sum([i for i in range(101)],100))
    
    # min 可以加key=函数  ***
    # max    ***
    # l1 = [3,4,1,2,7,-5]
    # print(min(l1))
    l1 = [('a',3),('b',2),('c',1)]
    # def func(x):
    #     '''
    #     x = (c,1)   1
    #     '''
    #     return x[1]
    # 改成lambda
    # func = lambda x : x[1]
    # # # print(lambda x : x[1])
    # # # print(func)
    # # print(min(l1,key=lambda x : x[1]))
    
    #
    # l1 = [i for i in range(10)]
    # # print(l1)
    # # print(reversed(l1))   ***
    # for i in reversed(l1):
    #     print(i)
    s = 'alex'
    # b = s.encode('utf-8')
    # s1 = b.decode('utf-8')
    
    # b = s.encode('utf-8')
    # print(b)
    # bs = bytes(s,encoding='utf-8')
    # print(bs)
    # print(chr(97))
    # print(chr(65))
    
    # repr
    # s1 = 'alex'
    # # print(s1)
    # # print(repr(s1))
    # s2 = '我叫%s'%('barry')
    # s2 = '我叫%r'%('barry')
    # print(s2)
    
    # sorted ***
    # l1 = [1,2,8,7,5]
    # print(min(l1))
    
    # l1 = [('c',2),('b',3),('a',1)]
    # # print(sorted(l1))
    # print(sorted(l1,key=lambda x:x[1]))
    
    # print(all([1,2,[1,2,3],'alex',True]))
    # print(any([1,'',[],(),False]))
    # zip 拉链方法  ***
    # l1 = [1,2,3,4]
    # tu1 = ('a','b','c')
    # tu2 = ('a1','b1','c1')
    # g = zip(l1,tu1,tu2)
    # # print(list(g))
    # for i in g:
    #     print(i)
    l1 = [1,2,3,4,5,6,7]
    # print([i for i in l1 if i > 3])
    # ret = filter(lambda x:x>3,l1)
    # # # print(ret)
    # # # print(list(ret))
    # [1,4,9,16,25]
    # map
    # print([i**2 for i in range(1,6)])
    # ret = map(lambda x:x*x,range(1,6))
    # print(list(ret))
    
    from functools import reduce
    
    # def func(x,y):
    #     return x + y  # 3
    ret = reduce(lambda x,y: x + y,[1,2,3,4,5])
    print(ret)
    匿名函数 和 一些内置函数 
    # -*- coding: utf-8 -*-
    # @Time    : 2019/1/27 9:42
    # @Author  : 景丽洋
    # @Email   : xxx@admin.com
    # @File    : 3.内容回顾.py
    # @Software: PyCharm
     
    # 函数进阶
    # 装饰器
        # 在不改变函数原本调用方式的基础上添加一些功能
        # @装饰器名
        # 如何写一个装饰器
        # 计算函数执行时间
        # 用户认证
        # 给函数添加日志
    # def wrapper(func):
    #     def inner(*args,**kwargs):
    #         '''在被装饰的函数之前添加功能'''
    #         ret = func(*args,**kwargs)
    #         '''在被装饰的函数之后添加功能'''
    #         return ret
    #     return inner
    #
    # @wrapper    # func = wrapper(func)
    # def func():
    #     pass
    # def wrapper2(func):
    #     def inner(*args,**kwargs):
    #         print('wrapper2 before')
    #         ret = func(*args,**kwargs)
    #         print('wrapper2 after')
    #         return ret
    #     return inner
    #
    # def wrapper1(func):
    #     def inner(*args,**kwargs):
    #         print('wrapper1 before')
    #         ret = func(*args,**kwargs)
    #         print('wrapper1 after')
    #         return ret
    #     return inner
    #
    # @wrapper2
    # @wrapper1    # func = wrapper(func)
    # def func():
    #     print('in func')
    # func()
     
    # 登陆 -- 装饰器 auth
    # 计算函数的执行时间 -- 装饰器 timmer
    # @auth
    # @timmer
    # def func():
    #     pass
     
    # flag = False
    # def outer(flag):
    #     def timmer(func):
    #         def inner(*args,**kwargs):
    #             if flag:
    #                 print('wrapper1 before')
    #                 ret = func(*args,**kwargs)
    #                 print('wrapper1 after')
    #             else:
    #                 ret = func(*args, **kwargs)
    #             return ret
    #         return inner
    #     return timmer
    #
    # @outer(flag)   #outer(flag) =  timmer    @outer(flag) =  @timmer
    # def func():
    #     print('in func')
    #
    # func()
     
     
    # 迭代器和生成器
    # 可迭代对象
    # 可迭代对象可以通过for/iter方法将一个可迭代对象转换成一个迭代器  ,list str range
    # 迭代器
    # 使用迭代器 : 节省内存,迭代器一项一项的取,节省内存 文件句柄
    # 生成器
        # 我们自己写的迭代器
        # 生成器的本质就是迭代器,所有的生成器都是迭代器
    # 实现生成器的方法 :
        # 生成器函数 :一定带yield关键字
        # g = func()
        # 生成器表达式 : 用小括号表示的推导式
    # 生成器的特点:
        # 1.可以用next/send方法从中取值
        # 2.生成器中的数据只能从头到尾取一次
        # 3.惰性运算 :不取生成器是不工作的
     
    # def demo():
    #     for i in range(4):
    #         yield i
    # g=demo()
    #
    # g2=(i for i in g)
    # g1=(i for i in g)
    #
    # print(list(g1))  # 0,1,2,3   # 这一步才开始从g1中取值
    # print(list(g2))  #
     
    # 列表推导式(排序)
        # [i**2 for i in lst]
        # [i**2 for i in lst if i%2 ==0 ]
    # 生成器表达式
        # (i**2 for i in lst)
     
    # 匿名函数
        # lambda 参数1,参数2,参数3 : 返回值/返回值相关的表达式
     
    # 内置函数
        # min max map filter sorted   单记
        # reduce --> functool
        # zip sum enumerate
    景丽洋的复习笔记

      

  • 相关阅读:
    文件上传与下载/Mail
    监听器/国际化
    过滤器
    父类转为子类涉及到的安全问题
    连接池
    【MySQL】Windows10下的安装与配置
    【neo4j】关于出现The old parameter syntax `{param}` is no longer supported. Please use `$param` instead的问题
    关于GitHub上传超过100M文件方法
    记录一次在知道创宇公司的实习面试经历
    《机器学习实战(基于scikit-learn和TensorFlow)》第七章内容学习心得
  • 原文地址:https://www.cnblogs.com/linux985/p/10332664.html
Copyright © 2020-2023  润新知