04---python基础(四)(装饰器-- (生成器/迭代器))

装饰器

在原有的函数前后增加功能,且不改变原函数的调用方式

  1. 计算一个函数的运行时间
import time
def timmer(f):
    def inner(*args,**kwargs):
        start_time = time.time()
        ret = f(*args,**kwargs)
        end_time = time.time()
        print(end_time - start_time)
        return ret
    return inner

@timmer   # func = timmer(func)
def func(a,b):
    print('begin func',a)
    time.sleep(0.1)
    print('end func',b)
    return True

ret = func(1,2)   #--> inner()

#begin func 1
#end func 2
#0.10142874717712402

2 . 进阶的需求

  1. 第一种情况:500个函数,你可以设计你的装饰器.来确认是否生效
import time
FLAG = True
def outer(flag):
    def timmer(f):
        def inner(*args,**kwargs):
            if flag == True:
                start_time = time.time()
                ret = f(*args,**kwargs)
                end_time = time.time()
                print(end_time - start_time)
            else:
                ret = f(*args, **kwargs)
            return ret
        return inner
    return timmer

@outer(FLAG)   # func = timmer(func)
def func(a,b):
    print('begin func',a)
    time.sleep(0.1)
    print('end func',b)
    return True

func(1,2)

#begin func 1
#end func 2
#0.10068607330322266

2 . 第二种情况

def wrapper1(func):
    def inner1():
        print('wrapper1 ,before func')
        func()
        print('wrapper1 ,after func')
    return inner1

def wrapper2(func):
    def inner2():
        print('wrapper2 ,before func')
        func()
        print('wrapper2 ,after func')
    return inner2

@wrapper2
@wrapper1
def f():
    print('in f')

f()

#wrapper2 ,before func
#wrapper1 ,before func
#in f
#wrapper1 ,after func
#wrapper2 ,after func

3 . 装饰器. 登录 . 记录日志

import time
login_info = {'alex':False}
def login(func):   # manager
    def inner(name):
        if login_info[name] != True:
            user = input('user :')
            pwd = input('pwd :')
            if user == 'alex' and pwd == 'alex3714':
                login_info[name] = True
        if login_info[name] == True:
            ret = func(name)     # timmer中的inner
            return ret
    return inner

def timmer(f):
    def inner(*args,**kwargs):
        start_time = time.time()
        ret = f(*args,**kwargs)     # 调用被装饰的方法
        end_time = time.time()      #
        print(end_time - start_time)
        return ret
    return inner

@login
@timmer
def index(name):
    print('欢迎%s来到博客园首页~'%name)

@login
@timmer    # manager = login(manager)
def manager(name):
    print('欢迎%s来到博客园管理页~'%name)

index('alex')
index('alex')
manager('alex')
manager('alex')

迭代器/生成器

迭代器


可迭代协议:内部含有iter方法的都是可迭代的
迭代器协议:内部含有iter方法和next方法的都是迭代器


如何从列表、字典中取值 #index 索引、 key、for循环
凡是可以使用for 循环取值的都是可迭代的

print (dir([1,2,3]))
#['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
lst_iter = [1,2,3].__iter__()
print(lst_iter.__next__())
print(lst_iter.__next__())
print(lst_iter.__next__())

#1
#2
#3

for i in [1,2,3]:   #  [1,2,3].__iter__()
    print(i)

#1
#2
#3

try: 的作用: 忽略指定的错误 except StopIteration:


虽然打印出来了,但是有报错

l = [1,2,3]
lst_iter = iter(l)   # l.__iter__()
while True:
    print(next(lst_iter)) # lst_iter.__next__() 

#1
#Traceback (most recent call last):
#2
# File "D:/python自动化/day04 笔记/4.迭代器和生成器.py", line 28, in <module>
#3
   print(next(lst_iter)) # lst_iter.__next__()
StopIteration
l = [1,2,3]
lst_iter = iter(l)   # l.__iter__()
while True:
    try:
        print(next(lst_iter)) # lst_iter.__next__()
    except StopIteration:
        break
#1
#2
#3

什么是可迭代的
什么是迭代器 迭代器 = iter(可迭代的),自带一个next方法
可迭代 最大的优势 节省内存

from collections import Iterable,Iterator
print(range(100000000))
print(isinstance(range(100000000),Iterable))
print(isinstance(range(100000000),Iterator))

#range(0,100000000)
#True
#False

py2 range 不管range多少 会生成一个列表 这个列表将用来存储所有的值
py3 range 不管range多少 都不会实际生成任何一个值


迭代器的优势
1. 节省内存
2. —快、取一个值就能进行接下来的计算 ,而不需要等到所有的值都计算出来才开始接下来的运算
迭代器的特性:惰性运算


生成器 (Generator)


自己写的迭代器,就是一个生成器
两种自己写的生成器(迭代器)的机制:生成器函数 生成器表达式

生成器函数

凡是带有yield 的函数就是一个生成器函数

def func():
    print('****')
    yield 1
    print('^^^^')
    yield 2   # 记录当前所在的位置,等待下一次next来触发函数的状态

g = func()
print('--',next(g))
print('--',next(g))

#****
#-- 1
#^^^^
#-- 2

生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器)
想要生成器函数执行,需要用next
想生成器中传递值 有一个激活的过程 第一次必须要用next触发这个生成器

def cloth_g(num):
    for i in range(num):
        yield 'cloth%s'%i


g = cloth_g(1000)
print(next(g))
print(next(g))
print(next(g))

#loth0
#loth1
#loth2

用生成器监听文件输入的例子

import time
def listen_file():
    with open('userinfo') as f:
        while True:
            line = f.readline()
            if line.strip():
                yield line.strip()
            time.sleep(0.1)

g = listen_file()
for line in g:
    print(line)

send 关键字

def func():
    print(11111)
    ret1 = yield 1
    print(22222,'ret1 :')
    ret2 = yield 2
    print(33333,'ret2 :',ret2)
    yield 3

g = func()
ret = next(g)
print(ret)
print(g.send('alex'))  # 在执行next的过程中 传递一个参数 给生成器函数的内部
print(g.send('金老板'))
#想生成器中传递值 有一个激活的过程 第一次必须要用next触发这个生成器

#11111
#1
#22222 ret1:
#2
#33333 ret2: 金老板
#3

计算移动平均值
12 13 15 18

def average():
    sum_money = 0
    day = 0
    avg = 0
    while True:
        money = yield avg
        sum_money += money
        day += 1
        avg = sum_money/day

g = average()
next(g)
print(g.send(200))
print(g.send(300))
print(g.send(600))

#200.0 
#250.0
#366.6666666666667

预激生成器

def init(func):
    def inner(*args,**kwargs):
        ret = func(*args,**kwargs)
        next(ret)  # 预激活
        return ret
    return inner

@init
def average():
    sum_money = 0
    day = 0
    avg = 0
    while True:
        money = yield avg
        sum_money += money
        day += 1
        avg = sum_money/day

g = average()
print(g.send(200))
print(g.send(300))
print(g.send(600))

#200.0
#250.0
#366.6666666666667

yield from

def generator_func():
    yield from range(5)
    yield from 'hello'
    for i in range(5):
        yield i
    for j in 'hello':
        yield j

g = generator_func()
for i in generator_func():
    print(i)

g1 = generator_func()
g2 = generator_func()
next(generator_func())
next(generator_func())

#0
#1
#2
#3
#4
#h
#e
#l
#l
#o
#0
#1
#2
#3
#4
#h
#e
#l
#l
#o

生成器小总结

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

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

列表推倒式

小例1

new_lst = []
for i in range(10):
    new_lst.append(i**2)
print(new_lst)    #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print([i**2 for i in range(10)])    #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

小例2

l = [1,2,3,-5,6,20,-7]
print([i%2 for i in range(10)])    #[0, 1, 0, 1, 0, 1, 0, 1, 0, 1]

l = [1,2,3,-5,6,20,-7]
print([num for num in l if num%2 == ) # [1, 3, -5, -7]

小题
30以内所有能被3整除的数

print([i for i in range(30) if i%3 ==0])

#[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]

30以内所有能被3整除的数的平方

print([i**2 for i in range(30) if i%3 ==0])
#[0, 9, 36, 81, 144, 225, 324, 441, 576, 729]

找到嵌套列表中名字含有两个‘e’的所有名字

names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
print([name for name_lst in names for name in name_lst if name.count('e') == 2])

#['Jefferson', 'Wesley', 'Steven', 'Jennifer']

生成器表达式

l = [i for i in range(30) if i%3 ==0]   # 列表推倒式 排序的时候
g = (i for i in range(30) if i%3 ==0)   # 生成器表达式 庞大数据量的时候 使用生成器表达式
print(l)
print(g)

#[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
#<generator object <genexpr> at 0x000001FD08C788E0>

面试题

def demo():
    for i in range(4):
        yield i

g=demo()

g1=(i for i in g)
g2=(i for i in g1)

print(list(g1))
print(list(g2))

def add(n,i):
    return n+i

def test():
    for i in range(4):
        yield i

g=test()
for n in [1,3,10]:
    g=(add(n,i) for i in g)

print(list(g))


#[0, 1, 2, 3]
#[]
#[30, 31, 32, 33]

一个生成器 只能取一次
生成器在不找他要值的时候始终不执行
当他执行的时候,要以执行时候的所有变量值为准

猜你喜欢

转载自blog.csdn.net/qq_40585450/article/details/80165713