装饰器,迭代器,生成器

装饰器

软件开发中的一个原则“开放-封闭”原则,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:

封闭:已实现的功能代码块不应该被修改

开放:对现有功能的扩展开放

装饰器特点:

  • 不修改被装饰对象的源代码
  • 不修改被装饰对象的调用方式
  • 被装饰函数的正上方,单独一行

 一、无参数装饰器

def hello_bye(func):
    def inner(*args,**kwargs):
        print("欢迎光临!!")
        result = func(*args,**kwargs)
        print("请慢走!!")
        return result
    return inner

@hello_bye  #shop 变成了 hello_bye(shop) ---> inner
def shop(goods):
    print("请拿好您购买的%s!!"%(goods))
    return 1

shop("鞋子")  #shop()变成 --->hello_bye(shop)() --->inner()
shop("衣服") 

 二、有参数装饰器(它比无参数的多了一层函数,用于传递参数)

def hello_bye(sex):
    def wrapper(func):
        def inner(*args,**kwargs):
            if sex == "先生":
                print("%s欢迎光临!!"%(sex))
                result = func(*args,**kwargs)
                print("赠送您一瓶饮料")
                print("%s请慢走!!"%(sex))
                return result
            elif sex == "女士":
                print("%s欢迎光临!!" % (sex))
                result = func(*args, **kwargs)
                print("赠送您一朵鲜花")
                print("%s请慢走!!" % (sex))
                return result
        return inner
    return wrapper

@hello_bye("女士")   # hello_bye("女士")返回wrapper,然后就和无参的装饰器一样了,它比无参数的多了一层函数,用于传递参数  
def shop1(goods):
    print("请拿好您购买的%s!!"%(goods))
    return 1

@hello_bye("先生")  
def shop2(goods):
    print("请不要在公共场合抽烟")
    print("请拿好您购买的%s!!" % (goods))
    return 1

shop1("鞋子")  
shop2("香烟")

三、多装饰器

@outer1
@outer2

def f1():
    print("hello!")
f1()

装饰后的效果等价于f1 = outer1(outer2(f1))。靠近的先装饰,然后当成函数再被装饰。

迭代器

迭代器通常要实现两个基本的方法: iter() next()

可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

可迭代对象

可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__

迭代器

内置有__iter__方法和__next__方法的对象

可迭代对象执行obj.__iter__()得到的结果就是迭代器对象。

生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

lis = [ x*2 for x in range(5)]  # 列表生成器
print(lis)

lis2 = ( x*2 for x in range(5)) # 创建一个generator
print(lis2)
# print(lis2.__next__())
# print(lis2.__next__())
for i in lis2:
    print(i)


[0, 2, 4, 6, 8]
<generator object <genexpr> at 0x0000000002025D58>
0
2
4
6
8

generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator

斐波拉契数列

函数1

def fib(num):
    n = 2
    fib_list = {}
    fib_list[1] = 1
    fib_list[2] = 1
    while n < num:
        n += 1
        fib_list[n] = fib_list[n-2] + fib_list[n-1]
    return fib_list[num]

print(fib(7))
13

 函数2

def fib(max):
    n, a, b = 0, 0, 1
    while n <max:
        print(b)
        a, b = b, a+b
        n+=1
    return b
fib(7)

1
1
2
3
5
8
13

要把函数变成generator,只需要把print(b)改为yield b就可以了:

def fib(max):
    n, a, b = 0, 0, 1
    while n <max:
        yield b
        a, b = b, a+b
        n+=1
    return b
ff = fib(7)
# print(ff.__next__())
# print(ff.__next__())
# print(ff.__next__())
# print(ff.__next__())
for i in ff:
    print(i)

 在每次调用next()的时候执行,遇到yield语句返回,再次被next()调用时从上次返回的yield语句处继续执行。

还可通过yield实现在单线程的情况下实现并发运算的效果  

import time
def consumer(name):
    print("%s 准备吃包子啦!" %name)
    while True:
       baozi = yield   

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))


def producer(name):
    c = consumer('A')
    c2 = consumer('B')
    c.__next__()
    c2.__next__()
    print("老子开始准备做包子啦!")
    for i in range(10):
        time.sleep(1)
        print("做了2个包子!")
        c.send(i)
        c2.send(i)

producer("alex")

yield可以接收send(i)发送的i。赋值给前面的变量baozi = yield

send(None) #对于表达式形式的yield,在使用时,第一次必须传None,send(None)等同于next(g)
 
 

猜你喜欢

转载自www.cnblogs.com/zhaohw127/p/10574461.html