我的python之路【第四章】装饰器、生成器、迭代器

装饰器:在遵循下面两个原则的前提下为被修饰者添加新功能
必须遵循两个原则
1、一定不能修改源代码
2、不能修改调用方式

下面有个函数index
def index(msg):
    print('this is index ',msg)

index('sasa')

我要为函数index加一个装饰器,获取程序执行的时间,但是不能修改源代码和函数的调用方式

import time
def timer(func):
    def wrapper(*args,**kwargs):    #'tom','xxxx'--->
        start_time=time.time()
        print(args)
        res=func(*args,**kwargs)    #这里是传入函数执行
        stop_time=time.time()
        print('run time is %s'%(stop_time-start_time))
        return "123"    ##加完装饰器的函数,返回值在这里定义
    return wrapper  

@timer  #index=timer(index)
def index(msg):
    print('this is index ',msg)

print(index('sasa'))

装饰器练习:

1、低级版,实现调用函数进行密码验证

def auth(func):
    def warrper(*args):
        name=input('input name: ')
        passwd=input('input passwd: ')
        if name=='alex' and passwd=='123':
            print('登录成功')
            func(*args)
        else:
            print('登录失败')
            return ''
    return warrper

@auth
def hello(msg):
    print("hello ",msg)
hello('Alex')

2、中级版(有参装饰器),实现采用不同方式进行用户验证

def auth_deco(auth_type='file'):
    def auth(func):
        def warrper(*args,**kwargs):
            name=input('input name: ')
            passwd=input('input passwd: ')
            if auth_type=='file':
                if name=='alex' and passwd=='123':
                    print('登录成功')
                    func(*args,**kwargs)
                else:
                    print('登录失败')
            elif auth_type=='ldap':
                print("用户验证ldap")
                func(*args,**kwargs)
        return warrper
    return auth
auth_type = 'ldap'
@auth_deco(auth_type)
def hello(msg):
    print("hello ",msg)
auth_type = 'ldap'
hello('alex')

3、思考题:高级版,验证一次,不需要一直验证。

 

生成器:

a=[1,2,3,4,5,6,7,8,9,10]

1、在我们生成列表时,系统会帮我们开辟一块内存空间来存储数据。当列表无限大的时候,这个列表占用的内存空间也会随之增大。

下面我们进行一个操作:将列表a中所有的元素进行加1生成一个新的列表。

#常规做法:循环列表重新为他进行赋值操作
for index,i in enumerate(a):
    a[index]=i+1
print(a)

 通过一种快捷的方法:列表生成式

# 列表生成式
a=[i+1 for i in a]
print(a)
#将列表中大于5的全部进行幂运算
a=[1,2,3,4,5,6,7,8,9,10]
a=[i*i if i >5 else i for i in a]
print(a)

以上的示范,你会发现这个列表a已经生成,此时它就会占用内存空间,这些有规律的列表我们可不可以让他在调用的时候才生成呢?

#列表生成器  #边执行边运算=惰性运算
a=(i*i if i >5 else i for i in a)
print(a)
#输出:<generator object <genexpr> at 0x000001D369B769E8>

将列表生成式的[]改成了(),此时的a变成了一个生成器。

生成器的特点

#提供next方法,来实现进行调用。编执行边运算,不知道下一个,上一个。只能一步步往下走。不知道尽头在哪儿里
#优点,不需要提前生成大量的数据来占用内存。节省内存。
#next() 和 a.__next__() 完全一样
print(next(a))
print(next(a))
print(next(a))
print(a.__next__())
#上面的next()方法太麻烦了。
#我们可以循环这个生成器来读取里面的内容
for i in a :
    print(i)

 斐波那契数列:除了第一个和第二个数,任意一个数都可由前两个数相加得到:

1、1、2、3、5、8、13、21、34、……

 让我们写一个函数实习这样的功能:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:    #max循环的次数
        print(b)
        #t=a+b
        #a=b
        #b=t
        a, b = b, a + b  
        n = n + 1  
    return 'done' 
f=fib(15)

输出:1 2 3 5 8 13 21  34 55 89 144 233 377 610

 

#将函数转换为生成器,yield
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'
#此时yield  已经将函数变成了生成器
f=fib(10)
print(f)
#<generator object fib at 0x000001A0D70D6A40>
#在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
print("可以在函数执行过程中做点别的事情")
print(f.__next__())
print(f.__next__())
print(f.__next__())
#循环读取生成器,此时生成器内的元素并没有占用内存空间
for i in fib(100):
    print(i)

通过yield实现在单线程的情况下实现并发运算的效果:生成者消费者模型
#通过yield实现在单线程的情况下实现并发运算的效果
import time

def xiaofeizhe(name):
    print("%s准备吃包子"%name)
    while True:
        baozi=yield
        print("来了第%s个包子, 被%s吃了"%(baozi,name))

def chushi(name):
    print("%s 开始做饭了"%name)
    x1=xiaofeizhe("贺磊")
    x2=xiaofeizhe("磊磊")
    x1.__next__()
    x2.__next__()
    for i in range(10):
        print("第%s个包子来了"%i)
        time.sleep(1)
        x1.send(i)
        x2.send(i)
chushi("浩哥")

迭代器:

  1. '''
    一类是集合数据类型,如list、tuple、dict、set、str等;
    
    一类是generator,包括生成器和带yield的generator function。
    
    这些可以直接作用于for循环的对象统称为可迭代对象:Iterable
    
    可以使用isinstance()判断一个对象是否是Iterable对象:
    
    '''
    from collections import Iterable
    print(isinstance([], Iterable))
    print(isinstance({}, Iterable))
    print(isinstance('abc', Iterable))
    print(isinstance((x for x in range(10)), Iterable))
    print(isinstance(100, Iterable))
    
    '''
    迭代器:*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
    生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
    可以使用isinstance()判断一个对象是否是Iterator对象
    '''
    from collections import Iterator
    print(isinstance((x for x in range(10)), Iterator))
    print(isinstance([], Iterator))
    print(isinstance({}, Iterator))
    print(isinstance('abc', Iterator))
    
    '''把list、dict、str等Iterable变成Iterator可以使用iter()函数'''
    print(isinstance(iter([]), Iterator))
    print(isinstance(iter([]), Iterator))

     

 

 























posted @ 2017-02-17 11:22  saynobody  阅读(176)  评论(0编辑  收藏  举报