迭代器,生成器,装饰器

迭代器:iterator

可迭代对象:iterable

从表现形式上看:能使用for循环迭代的,就是可迭代对象!
	(字符串,列表,字典,集合,元组.)
它们都有一个方法:__iter__,魔法方法,推荐使用iter(x)
iter(x) -> 得到的是一个绑定到当前可迭代对象身上的迭代器!!!
for循环实际上干了两件事:
1.获取可迭代对象的迭代器.
2.通过迭代器遍历可迭代对象!!!
迭代器:实现了__iter__,__next__方法的对象(也称为实现了迭代器协议.),就是迭代器.
这两个方法是魔法方法(Python中不推荐直接使用的),推荐使用替代方法:
iter(x)		-> 返回的就是这个迭代器本身.
next(x)		-> 返回的是下一个可用元素.
lst = [1,2,3]
# 获取到迭代器对象
i = iter(lst)
# 使用迭代器的next方法,依次获取元素
print(next(i))
print(next(i))
手动使用next方法有个缺点:没有办法很好的控制边界!!!
使用for循环可以自动判定边界.

可迭代对象和迭代器的关系:

可迭代对象每次调用iter方法,获取的都是新的迭代器.

如何验证一个对象是可迭代的?还是迭代器?

from  collections import Iterator,Iterable

print(isinstance([1,2,3],Iterable))	True
print(isinstance([1,2,3],Iterator))	False

生成器:generator

一种流式生成数据的方式:

流式产生数据:保存的不是真实的数据,而是产生数据的方式!!

python2和python3中使用range时
python2中会直接生成数据,数据大容易崩(非常占内存)
python3中只是生成了range的范围,也就是上面所说的方式

好处:节省内存!!!!

自定义生成器(函数):

包含了yield关键字的函数,就是生成器函数.

def my_generator():
	yield 10

def my_generator():
	for x in range(100):
		yield x

生成器本质上就是迭代器:

# 借助collections包中的Iterator类,
from  collections import Iterator,Iterable
print(isinstance(g,Iterator))

# 既然是迭代器,就使用for循环迭代!!
for x in g:
    print(x)

for循环本质上就是调用生成器的next方法,即:

第一种触发生成器的方式:使用next方法!!!

带有赋值语句的生成器:

第一次比较特殊:只执行一,三部分

从第二次开始:一,二,三执行.

...

第二种触发生成器的方式:使用send方法.

根据定义时是否有赋值语句,以及两种触发方式:一共有四种组合!!!

1.没有赋值语句,使用next触发
def my_generator():
    for x in range(5):
        yield x

g = my_generator()
print(next(g))
print(next(g))
print(next(g))
print(next(g))

2.没有赋值语句,使用send触发
def my_generator():
    for x in range(5):
        yield x

g = my_generator()
print(g.send(None))
print(g.send(10))
print(g.send(20))
print(g.send(30))
由于没有变量接收,传递的值,实际上都丢弃了!!!

3.有赋值语句,使用next触发
# 有赋值语句,使用next触发
def my_generator(n):
    for x in range(n+1):
        n = yield x
        print(n)


g = my_generator(5)
print(next(g))
print(next(g))
print(next(g))
由于没有使用send,使用next方法,实际上每次都是传递的None

4.有赋值语句,使用send触发
def my_generator(n):
    total = 0
    for x in range(n+1):
        n = yield total
        total += n

g = my_generator(5)
print(g.send(None))
print(g.send(1))
print(g.send(2))
print(g.send(3))
print(g.send(4))


应用:

# 计算移动平均值!
def my_generator(n):
    total = 0
    count = 0
    avg = 0
    for x in range(n+1):
        n = yield avg
        total += n
        count += 1
        avg = total / count


g = my_generator(5)
print(g.send(None))
print(g.send(10))
print(g.send(20))
print(g.send(30))
print(g.send(40))

总结:

包含yield关键字的函数定义,就是生成器函数,生成器函数也是一个迭代器!
生成器函数的使用:
通常情况下,是使用for循环的方式使用生成器.实际底层使用的是迭代器的next方法.所以,也可以使用next()方法直接触发生成器产生一个值.

针对是否有赋值语句,以及是否使用传值的方式触发生成器,一共有四种形式:

1.没有赋值语句,使用next方法触发
2.没有赋值语句,使用send方法触发.此时实际上传递的值都被丢弃掉了.
3.有赋值语句,使用next方法触发,此时实际上传递的都是None值.
4.有赋值语句,使用send方法触发,此时值才被真正的传递给了yield表达式中.

注意有赋值语句的表达式的执行顺序问题:
第一次使用send赋值,只能是None值,或者使用next方法触发,实际上也是传递了None值.
从第二次开始,可以传递有意义的值.
执行的顺序是:先给赋值语句左侧的变量赋值,然后执行yield语句下面的语句,最后返回的是yield关键字后面的值.

装饰器:decorator

对原函数进行功能上的增强!

def wrapper(fn):
    # return fn

    # 定义嵌套函数,
    def inner(*args,**kwargs):
        # 对原始函数的调用
        ret = fn(*args,**kwargs)
        # 对原始函数的返回值进行处理
        if ret < 0:
            return -ret
        else :
            return ret

    # 把嵌套函数返回
    return inner

@wrapper
def func(a,b):
    return a - b


print(func(5,3))
print(func(5,30))

多层

# 定义装饰器
def w(min_value,max_value):
    def wrapper(fn):
        # return fn

        # 定义嵌套函数,
        def inner(*args,**kwargs):
            # 对原始函数的调用
            ret = fn(*args,**kwargs)
            # 对原始函数的返回值进行处理
            if ret < min_value:
                return min_value
            elif ret > max_value:
                return max_value

        # 把嵌套函数返回
        return inner

    return wrapper


@w(-5,5)
def fun(a,b):
    return a + b



总结:

装饰器函数一定是一个闭包函数,在函数内部定义一个函数,并返回.

def wrapper(fn):
def inner(*args,**kwargs):
print('hello')  		# 前置增强写在这里
ret = fn(*args,**kwargs)	# 原始函数调用在这里
return ret
return inner


装饰器函数的两种使用方式:
1.在被装饰的函数上使用@装饰器名
2.使用普通的函数名绑定的方式
func = wrapper(func)

不论哪种方式,目的都是一个,让装饰器函数返回的函数绑定回原始的函数名.

注意:装饰器函数中的可执行语句会被马上执行!!!

带有参数的函数装饰器(三层函数的嵌套)

posted @ 2019-04-09 17:18  blog_wu  阅读(209)  评论(0编辑  收藏  举报