装饰器
软件开发中的一个原则“开放-封闭”原则,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
封闭:已实现的功能代码块不应该被修改
开放:对现有功能的扩展开放
装饰器特点:
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
- 被装饰函数的正上方,单独一行
一、无参数装饰器
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
循环的数据类型有以下几种:
一类是集合数据类型,如list
、tuple
、dict
、set
、str
等;
一类是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)