• forth day--装饰器、迭代器、生成器


    python一定会用到装饰器
     1 # 装饰器
     2 # 在原有的函数前后增加功能,且不改变原函数的调用方式
     3 
     4 # 计算一个函数的运行时间
     5 # import time
     6 # def timmer(f):
     7 #     def inner(*args,**kwargs):
     8 #         start_time = time.time()
     9 #         ret = f(*args,**kwargs)
    10 #         end_time = time.time()
    11 #         print(end_time - start_time)
    12 #         return ret
    13 #     return inner
    14 #
    15 # @timmer   # func = timmer(func)
    16 # def func(a,b):
    17 #     print('begin func',a)
    18 #     time.sleep(0.1)
    19 #     print('end func',b)
    20 #     return True
    21 #
    22 # ret = func(1,2)   #--> inner()
    23 
    24 
    25 # def timmer(f):
    26 #     def inner(*args,**kwargs):
    27 #
    28 #         ret = f(*args,**kwargs)
    29 #
    30 #         return ret
    31 #     return inner
    装饰器初识

    1.装饰器的进阶
    1.设计装饰器确认是否生效 定义一个装饰器传参数
    outer()
     1 # 进阶的需求
     2 # 第一种情况
     3 #     500个函数
     4 #     你可以设计你的装饰器 来确认是否生效
     5 
     6 # import time
     7 # FLAG = True
     8 # def outer(flag):
     9 #     def timmer(f):
    10 #         def inner(*args,**kwargs):
    11 #             if flag == True:
    12 #                 start_time = time.time()
    13 #                 ret = f(*args,**kwargs)
    14 #                 end_time = time.time()
    15 #                 print(end_time - start_time)
    16 #             else:
    17 #                 ret = f(*args, **kwargs)
    18 #             return ret
    19 #         return inner
    20 #     return timmer
    21 #
    22 # @outer(FLAG)   # func = timmer(func)
    23 # def func(a,b):
    24 #     print('begin func',a)
    25 #     time.sleep(0.1)
    26 #     print('end func',b)
    27 #     return True
    28 #
    29 # func(1,2)
    往装饰器中传参数

    2.装饰器 登录 记录日志
     1 # 第二种情况
     2 def wrapper1(func):
     3     def inner1():
     4         print('wrapper1 ,before func')
     5         func()
     6         print('wrapper1 ,after func')
     7     return inner1
     8 
     9 def wrapper2(func):
    10     def inner2():
    11         print('wrapper2 ,before func')
    12         func()
    13         print('wrapper2 ,after func')
    14     return inner2
    15 
    16 @wrapper2
    17 @wrapper1
    18 def f():
    19     print('in f')
    20 
    21 # f()
    多个装饰器装饰一个函数小例子

    自动登录!@login 单点登录(不加timer时)

    登录,计算index和manager执行时间 :在写一个装饰器timer
    多个装饰器,从下开始执行
     1 # 装饰器 登录 记录日志
     2 import time
     3 login_info = {'alex':False}
     4 def login(func):   # manager
     5     def inner(name):
     6         if login_info[name] != True:
     7             user = input('user :')
     8             pwd = input('pwd :')
     9             if user == 'alex' and pwd == 'alex3714':
    10                 login_info[name] = True
    11         if login_info[name] == True:
    12             ret = func(name)     # timmer中的inner
    13             return ret
    14     return inner
    15 
    16 def timmer(f):
    17     def inner(*args,**kwargs):
    18         start_time = time.time()
    19         ret = f(*args,**kwargs)     # 调用被装饰的方法
    20         end_time = time.time()      #
    21         print(end_time - start_time)
    22         return ret
    23     return inner
    24 
    25 @login
    26 @timmer
    27 def index(name):
    28     print('欢迎%s来到博客园首页~'%name)
    29 
    30 @login
    31 @timmer    # manager = login(manager)
    32 def manager(name):
    33     print('欢迎%s来到博客园管理页~'%name)
    34 
    35 index('alex')
    36 index('alex')
    37 manager('alex')
    38 manager('alex')
    39 
    40 # 计算index 和 manager的执行时间
    登录计算时间
    2.迭代器
    从列表中取值
    可迭代的
    可迭代协议:__iter__方法
    迭代器协议:__iter__和__next__方法

    iter
    while True
    try---except异常处理
    迭代器节省内存,快 iterable 可迭代的 iterator迭代器
    py2 range
    py3 range
    迭代器特性:惰性运算
    小例子
    for line in f:(f至少是可迭代的)
    列表字典 元祖字符串 集合 range 文件句柄 enumerate
     1 # 迭代器
     2 # 如何从列表、字典中取值的
     3     # index索引 ,key
     4     # for循环
     5 # 凡是可以使用for循环取值的都是可迭代的
     6 # 可迭代协议 :内部含有__iter__方法的都是可迭代的
     7 # 迭代器协议 :内部含有__iter__方法和__next__方法的都是迭代器
     8 # print(dir([1,2,3]))
     9 # lst_iter = [1,2,3].__iter__()
    10 # print(lst_iter.__next__())
    11 # print(lst_iter.__next__())
    12 # print(lst_iter.__next__())
    13 # for i in [1,2,3]:   #  [1,2,3].__iter__()
    14 #     print(i)
    15 # l = [1,2,3]
    16 # lst_iter = iter(l)   # l.__iter__()
    17 # while True:
    18 #     try:
    19 #         print(next(lst_iter)) # lst_iter.__next__()
    20 #     except StopIteration:
    21 #         break
    22 
    23 # 什么是可迭代的
    24 # 什么是迭代器     迭代器 = iter(可迭代的),自带一个__next__方法
    25 # 可迭代 最大的优势 节省内存
    26 # from collections import Iterable,Iterator
    27 # print(range(100000000))            #range(0, 100000000)
    28 # print(isinstance(range(100000000),Iterable))   #True
    29 # print(isinstance(range(100000000),Iterator))    #False
    30 # py2 range 不管range多少 会生成一个列表 这个列表将用来存储所有的值
    31 # py3 range 不管range多少 都不会实际的生成任何一个值
    32 # 迭代器的优势:
    33 #     节省内存
    34 #     取一个值就能进行接下来的计算 ,而不需要等到所有的值都计算出来才开始接下来的运算 —— 快
    35 # 迭代器的特性:惰性运算
    36 
    37 # f = open()
    38 # for line in f:
    39 
    40 # 列表 字典 元组 字符串 集合 range 文件句柄 enumerate
    讲课笔记
    3.生成器generator
    自己写的迭代器 就是一个生成器
    两种自己写生成器(迭代器)的机制:生成器函数 生成器表达式
    做衣服的例子 2000000 分批取
    # 200 0000
    # 牛翔  200 0000
    # 40期
    # 赵英杰 200 0000
    # 21 60  60件衣服
    # 200 0000 - 60
    # 500期  0
    # 501
    
    # def cloth(num):
    #     ret = []
    #     for i in range(num):
    #         ret.append('cloth%s'%i)
    #     return ret
    View Code

    yield凡是带有yield的函数就是生成器函数
    生成器函数的调用不会触发代码的执行,而是返回一个生成器(迭代器) 加next取值
    yield记录当前位置,等下一个next触发
     1 # 凡是带有yield的函数就是一个生成器函数
     2 # def func():
     3 #     print('****')
     4 #     yield 1
     5 #     print('^^^^')
     6 #     yield 2   # 记录当前所在的位置,等待下一次next来触发函数的状态
     7 #
     8 # g = func()
     9 # print('--',next(g))   #****
    10                         #-- 1
    11 # print('--',next(g))    #^^^^
    12                         #-- 2
    13 # 生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器)
    14 # 想要生成器函数执行,需要用next
    15 # def cloth_g(num):
    16 #     for i in range(num):
    17 #         yield 'cloth%s'%i
    18 #
    19 # g = cloth_g(1000)
    20 # print(next(g))    #cloth0
    21 # print(next(g))    #cloth1
    22 # print(next(g))    #cloth2
    概念+next

    生成器函数
    多个next例子
    使用生成器监听文件输入的例子,图片未保存看视频! 写入文件需要保存(无法用函数去做,函数无法监听)----实现记录日志
    mac本中关闭文件才认为保存。
     1 # 使用生成器监听文件输入的例子
     2 # import time
     3 # def listen_file():
     4 #     with open('userinfo') as f:
     5 #         while True:
     6 #             line = f.readline()
     7 #             if line.strip():
     8 #                 yield line.strip()
     9 #             time.sleep(0.1)
    10 #
    11 # g = listen_file()
    12 # for line in g:
    13 #     print(line)
    使用生成器监听文件输入的例子

    send关键字:例子
    定义:在执行next的过程中 传递一个参数 给生成器函数的内部
    分析执行图片
    向内部传参
    send 不能用在第一次传值,必须next;send传给yield后的返回值
     1 # send关键字
     2 # def func():
     3 #     print(11111)
     4 #     ret1 = yield 1
     5 #     print(22222,'ret1 :',ret1)
     6 #     ret2 = yield 2
     7 #     print(33333,'ret2 :',ret2)
     8 #     yield 3
     9 #
    10 # g = func()
    11 # ret = next(g)
    12 # print(ret)
    13 # print(g.send('alex'))  # 在执行next的过程中 传递一个参数 给生成器函数的内部
    14 # print(g.send('金老板'))
    15 # 想生成器中传递值 有一个激活的过程 第一次必须要用next触发这个生成器
    send概念

    #例子 计算移动平均值!!
    月度的天平均收入 def average():
    注意开始day=0报错的处理 分析图片
     1 # 例子
     2 # 计算移动平均值
     3 # 12 13 15 18
     4 # 月度 的 天平均收入
     5 # def average():
     6 #     sum_money = 0
     7 #     day = 0
     8 #     avg = 0
     9 #     while True:
    10 #         money = yield avg
    11 #         sum_money += money
    12 #         day += 1
    13 #         avg = sum_money/day
    14 #
    15 # g = average()
    16 # next(g)
    17 # print(g.send(200))
    18 # print(g.send(300))
    19 # print(g.send(600))
    例子--月度 的 天平均收入

    预激生成器 next(g) 放在装饰器中 看思考题面试最后一道
     1 # 预激生成器
     2 # def init(func):
     3 #     def inner(*args,**kwargs):
     4 #         ret = func(*args,**kwargs)
     5 #         next(ret)  # 预激活
     6 #         return ret
     7 #     return inner
     8 #
     9 # @init
    10 # def average():
    11 #     sum_money = 0
    12 #     day = 0
    13 #     avg = 0
    14 #     while True:
    15 #         money = yield avg
    16 #         sum_money += money
    17 #         day += 1
    18 #         avg = sum_money/day
    19 #
    20 # g = average()
    21 # print(g.send(200))
    22 # print(g.send(300))
    23 # print(g.send(600))
    预激生成器-天平均例子加装饰器预激活

    yield from
    例子 range从0开始取值
    yield from range(5) ---->
    for i in range(5):
    print(i)
    g=generator_func() 与放print中区别,放在print中一直打印0
    g取得不同的内存
     1 # yield from
     2 def generator_func():
     3     yield from range(5)
     4     yield from 'hello'
     5     # for i in range(5):
     6     #     yield i
     7     # for j in 'hello':
     8     #     yield j
     9 
    10 # g = generator_func()
    11 # for i in generator_func():
    12 #     print(i)
    13 
    14 # g1 = generator_func()
    15 # g2 = generator_func()
    16 # next(generator_func())
    17 # next(generator_func())
    yield from

    如何从生成器取值
    next :随时停止,最后一次会报错,不知道在哪儿停
    for循环:从头到尾遍历一次,不遇到break、return不停止
    list、tuple:把所有数据类型都放在list中,浪费内存
    # 如何从生成器中取值
    # 第一种 :next  随时都可以停止 最后一次会报错
    # print(next(g))
    # print(next(g))
    # 第二种 :for循环 从头到尾遍历一次 不遇到break、return不会停止
    # for i in g:
    #     print(i)
    # 第三种 :list tuple 数据类型的强转  会把所有的数据都加载到内存里 非常的浪费内存
    # print(g)
    # print(list(g))
    View Code

    总结:有yield。。。
    生成器用途2个图片
    1 # 生成器函数 是我们python程序员实现迭代器的一种手段
    2 # 主要特征是 在函数中 含有yield
    3 # 调用一个生成器函数 不会执行这个函数中的带码 只是会获得一个生成器(迭代器)
    4 # 只有从生成器中取值的时候,才会执行函数内部的带码,且每获取一个数据才执行得到这个数据的带码
    5 # 获取数据的方式包括 next send 循环 数据类型的强制转化
    6 # yield返回值的简便方法,如果本身就是循环一个可迭代的,且要把可迭代数据中的每一个元素都返回 可以用yield from
    7 # 使用send的时候,在生成器创造出来之后需要进行预激,这一步可以使用装饰器完成
    8 # 生成器的特点 : 节省内存 惰性运算
    9 # 生成器用来解决 内存问题 和程序功能之间的解耦
    小结


    生成器表达式
    推导过程例子
    完整的列表推导式
    #30以内能被3整除的数
    print([i for i in range(30) if i%3==0])
    #30以内能被3整除的数的平方
    print([i**2 for i in range(30) if i%3==0])
    两个for也可以
    研究集合、字典推导式---不常用
     1 # 列表推倒式
     2 # new_lst = []
     3 # for i in range(10):
     4 #     new_lst.append(i**2)
     5 # print(new_lst)
     6 # print([i**2 for i in range(10)])
     7 # l = [1,2,3,-5,6,20,-7]
     8 # print([i%2 for i in range(10)])
     9 # l = [1,2,3,-5,6,20,-7]
    10 # print([num for num in l if num%2 == 1])
    11 
    12 # 30以内所有能被3整除的数
    13 # print([i for i in range(30) if i%3 ==0])
    14 #
    15 # 30以内所有能被3整除的数的平方
    16 # print([i**2 for i in range(30) if i%3 ==0])
    17 
    18 # 找到嵌套列表中名字含有两个‘e’的所有名字
    19 # names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
    20 #          ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    21 # print([name for name_lst in names for name in name_lst if name.count('e') == 2])
    列表推导式
    
    
         列表推导式[] 排序的时候
            生成器表达式()   数据量庞大的时候用
    1 # 生成器表达式
    2 # l = [i for i in range(30) if i%3 ==0]   # 列表推倒式 排序的时候
    3 # g = (i for i in range(30) if i%3 ==0)   # 生成器表达式 庞大数据量的时候 使用生成器表达式
    4 # print(l)
    5 # print(g)
    6 # for i in g:print(i)
    对比

    面试题
    1.list时真正执行  一个生成器只能取一次
     1 # def demo():
     2 #     for i in range(4):
     3 #         yield i
     4 #
     5 # g=demo()
     6 #
     7 # g1=(i for i in g)
     8 # g2=(i for i in g1)
     9 #
    10 # print(list(g1))   #[0,1,2,3]
    11 # print(list(g2))   #[]
    1
    2.[20,21,22,23]重点理解生成器什么时候执行!!
    生成器在不找它要值的时候始终不执行
    执行时候,要以执行变量值为准
    [1,3,10] [30,31,32,33]
     1 # mianshiti2
     2 # def add(n,i):
     3 #     return n+i
     4 #
     5 # def test():
     6 #     for i in range(4):
     7 #         yield i
     8 #
     9 # g=test()
    10 # for n in [1,10]:
    11 #     g=(add(n,i) for i in g)
    12 #
    13 # print(list(g))
    2
    
    
     1 def add(n,i):
     2     return n+i
     3 
     4 def test():
     5     for i in range(4):
     6         yield i
     7 
     8 g=test()
     9 # for n in [1,10]:
    10 #     g=(add(n,i) for i in g)
    11 # n=1
    12 # g=(add(n,i) for i in g)
    13 n=10
    14 #g = (add(n, i) for i in add(n,i) for i in test())
    15 # g = (add(10, i) for i in add(10,i) for i in [0,1,2,3])
    16 g = (add(10, i) for i in [10,11,1213])
    17 print(list(g)) [20,21,22,23]
    详解

    3.面试题3,看懂即可!
     1 import os
     2 
     3 def init(func):
     4     def wrapper(*args,**kwargs):
     5         g=func(*args,**kwargs)
     6         next(g)
     7         return g
     8     return wrapper
     9 
    10 @init
    11 def list_files(target):
    12     while 1:
    13         dir_to_search=yield
    14         for top_dir,dir,files in os.walk(dir_to_search):
    15             for file in files:
    16                 target.send(os.path.join(top_dir,file))
    17 @init
    18 def opener(target):
    19     while 1:
    20         file=yield
    21         fn=open(file)
    22         target.send((file,fn))
    23 @init
    24 def cat(target):
    25     while 1:
    26         file,fn=yield
    27         for line in fn:
    28             target.send((file,line))
    29 
    30 @init
    31 def grep(pattern,target):
    32     while 1:
    33         file,line=yield
    34         if pattern in line:
    35             target.send(file)
    36 @init
    37 def printer():
    38     while 1:
    39         file=yield
    40         if file:
    41             print(file)
    42 
    43 g=list_files(opener(cat(grep('python',printer()))))
    44 
    45 g.send('/test1')
    46 
    47 协程应用:grep -rl /dir
    tail&grep
     
  • 相关阅读:
    NStimer 被堵塞
    零基础学python-7.6 字符串格式化表达式
    实验记录三 通用输入输出(GPIO)
    VTK的安装配置-使用VS2010
    Python 查找Twitter中特定话题中最流行的10个转发Tweet
    ios开发之-计算器的改进
    彻查网络局部网段内Ping时断时续的问题
    hdoj-1016-Prime Ring Problem【深搜】
    WebView的截屏实现
    CentOs虚拟机能够互相ping通,但无法訪问虚拟机服务
  • 原文地址:https://www.cnblogs.com/lijie123/p/8922145.html
Copyright © 2020-2023  润新知