Python基础12-迭代器、生成器和装饰器

迭代器

迭代是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合。

特点:

  1. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
  2. 迭代器只能往前访问元素不会后退
  3. 便于循环比较大的数据集合,节省内存
  4. 迭代器有两个基本的方法:iter() 和 next(),通过iter()生成迭代器,通过next()访问下一个元素

 

字符串,列表或元组对象都可用于创建迭代器:

>>>list=[1,2,3,4]
>>> it = iter(list)    # 创建迭代器对象
>>> print(it)
<list_iterator object at 0x0000000001102BA8>
>>> print (next(it))   # 输出迭代器的下一个元素
1
>>> print (next(it))
2
>>>

 

迭代器对象可以使用常规for语句进行遍历:

list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
for x in it:
    print (x, end=" ")

迭代器对象也可以使用 next() 进行遍历:

import sys         # 引入 sys 模块
 
list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
 
while True:
    try:
        print (next(it))
    except StopIteration:
        sys.exit()

 

 

生成器

在 Python 中,使用了 yield 的函数被称为生成器(generator)。

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

调用一个生成器函数,返回的是一个迭代器对象。

使用生成器实现斐波那契数列:

import sys
 
def fibonacci(n): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
 
while True:
    try:
        print (next(f), end=" ")
    except StopIteration:
        sys.exit()

 

生成器方法send()

def MyGenerator():
    value = (yield 1)
    print("value:{}".format(value))
    value = (yield value)
    print("value:{}".format(value))

gen = MyGenerator()
print(gen.__next__())
print(gen.send(2))
print(gen.send(3))

运行结果与解释

1
value:2
2
value:3
  File "C:/Project/test.py", line 308, in <module>
    print(gen.send(3))
StopIteration

上面代码的运行过程如下。
当调用gen._next()_方法时,python首先会执行MyGenerator方法的yield 1语句。由于是一个yield语句,因此方法的执行过程被挂起,而next方法返回值为yield关键字后面表达式的值,即为1,
打印1。 当调用gen.send(2)方法时,python首先恢复MyGenerator方法的运行环境。同时,将表达式(yield 1)的返回值定义为send方法参数的值,即为2。这样,接下来value=(yield 1)这一赋值语句
会将value的值置为2,打印value:2。继续运行会遇到yield value语句。因此,MyGenerator方法再次被挂起。同时,send方法的返回值为yield关键字后面表达式的值,也即value的值,为2,打印2。 当调用send(3)方法时MyGenerator方法的运行环境。同时,将表达式(yield value)的返回值定义为send方法参数的值,即为3。这样,接下来value=(yield value)这一赋值语句会将value的值
置为3,打印value:3。继续运行,MyGenerator方法执行完毕,故而抛出StopIteration异常。

总的来说,send方法和next方法唯一的区别是在执行send方法会首先把上一次挂起的yield语句的返回值通过参数设定,从而实现与生成器方法的交互。但是需要注意,在一个生成器对象没有执行next方法之前,由于没有yield语句被挂起,所以执行send方法会报错。例如

gen = MyGenerator()  
print(gen.send(2))

上面代码的输出为

Traceback (most recent call last):  
  File "test.py", line 16, in <module>  
    print gen.send(2)  
TypeError: can't send non-None value to a just-started generator  

但是,上面代码是可以运行的

gen = MyGenerator()  
print gen.send(None)

当send方法的参数为None时,它与next方法完全等价。但是注意,虽然上面的代码可以接受,但是不规范。所以,在调用send方法之前,还是先调用一次next方法为好。

 

 

装饰器

在不影响原有函数代码及执行方法的前提下,在函数前增加代码功能。

通过一下代码例子讲解:

def w1(func):
    def inner():
        # 验证
        return func()
    return inner
 
@w1
def f1():
    print 'f1'

当写完这段代码后(函数未被执行),python解释器就会从上到下解释代码,步骤如下:

  1. def w1(func):  ==>将w1函数加载到内存
  2. @w1

没错,从表面上看解释器仅仅会解释这两句代码,因为函数在没有被调用之前其内部代码不会被执行。

从表面上看解释器着实会执行这两句,但是 @w1 这一句代码里却有大文章,@函数名 是python的一种语法糖。

如上例@w1内部会执行一下操作:

    • 执行w1函数,并将 @w1 下面的 函数 作为w1函数的参数,即:@w1 等价于 w1(f1)
      所以,内部就会去执行:
          def inner:
              #验证
              return f1()   # func是参数,此时 func 等于 f1
          return inner     # 返回的 inner,inner代表的是函数,非执行函数
      其实就是将原来的 f1 函数塞进另外一个函数中
    • 将执行完的 w1 函数返回值赋值给@w1下面的函数的函数名
      w1函数的返回值是:
         def inner:
              #验证
              return 原来f1()  # 此处的 f1 表示原来的f1函数
      然后,将此返回值再重新赋值给 f1,即:
      新f1 = def inner:
                  #验证
                  return 原来f1() 
      所以,以后业务部门想要执行 f1 函数时,就会执行 新f1 函数,在 新f1 函数内部先执行验证,再执行原来的f1函数,然后将 原来f1 函数的返回值 返回给了业务调用者。
      如此一来, 即执行了验证的功能,又执行了原来f1函数的内容,并将原f1函数返回值 返回给业务调用

 

可以装饰具有处理n个参数的函数的装饰器

def w1(func):
    def inner(*args,**kwargs):
        # 验证
        return func(*args,**kwargs)
    return inner
 
@w1
def f1(arg1,arg2,arg3):
    print 'f1'

 

在定义装饰器时,也可以带入参数

user,passwd = 'chen71','chen71'
def auth_func(auth_type):        #接收装饰器的参数auth_type
    def out_wrapper(func):
        def wrapper(*args,**kwargs):
            if auth_type == 'local':
                username = input('username:')
                password = input('password:')
                if user == username and passwd == password:
                    print('Welcome...')
                    return func(*args,**kwargs)
                else:
                    print('Wrong username or password')
            elif auth_type == 'net':
                print('Sorry,net is not working...')
        return wrapper
    return out_wrapper

def index():
    print('Welcome to index page...')

@auth_func(auth_type = 'local')     #指定装饰器的参数
def home():
    print('Welcome to home page...')

@auth_func(auth_type = 'net')
def bbs():
    print('Welcome to bbs page...')

index()
home()
bbs()

 

一个函数应用多个装饰器

def w1(func):
    def inner1(*args,**kwargs):
        print('w1_1')
        func(*args,**kwargs)
        print('w1_2')
    return inner1

def w2(func):
    def inner2(*args,**kwargs):
        print('w2_1')
        func(*args,**kwargs)
        print('w2_2')
    return inner2
@w1
@w2
def f1(name):
    print('f1')
    print('arg:{}'.format(name))

运行结果

w1_1
w2_1
f1
arg:hello
w2_2
w1_2

  

调用过程:函数先应用w1,调用inner1打印出w1_1,inner1执行过程中调用w2的inner2,inner2执行过程中调用f1,inner2执行完毕之后,跳转回inner1继续往下执行打印w1_2

 

参考链接:http://www.cnblogs.com/wupeiqi/articles/4980620.html

参考链接:http://blog.csdn.net/xionghuixionghui/article/details/65442554

转载于:https://www.cnblogs.com/chenqiyi/p/8484869.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值