装饰器,迭代器与生成器

python学习网 2017-07-28 13:12:02

装饰器

  从一个简单的计时功能来了解装饰器的功能与基本概念。  

import time
def  foo():
    time.sleep(2)
    print("Hello world!")
foo()

  这是一个简单的打印延时程序,现在想要计算出程序运行的过程用了多长时间,并且不改动源代码,这时候就需要使用装饰器来完成需求了。

import time
def timmer(func):
    def wrapper():
        """计时功能"""
        time_start=time.time()
        func()
        time_end=time.time()
        print("Run time is %s "%(time_end-time_start))
    return wrapper
@timmer
def  foo():
    time.sleep(2)
    print("Hello world!")
foo()

  在这个函数中,只是加入了一个@timmer就使得没有更改原程序代码而直接增加了一个计时的功能,这真的是有些神奇呢,那这个所谓的装饰器是怎样工作的呢?

  @timmer其实是调用装饰器的语法,在调用前我们必须遵守先定义再调用的原则,@timmer其实相当于foo=timmer(foo),程序运行timmer函数,将foo作为参数func,定义函数wrapper并返回wrapper的地址空间,运行foo()其实就是运行了wrapper,而wrapper中的func()就是foo(),运行前后的时间差打印出来,就是我们要的计时功能了。

  因为这里我们定义的foo()是一个无参函数,无需传递参数,当我们需要传递参数时,则需要将wrapper后加入动态参数*args,**kwargs来接收传入的参数。

  有参装饰器

def auth(func):
    def wrapper(*args, **kwargs):
        username = input("Please input your username:")
        passwd = input("Please input your password:")
        if passwd == '123' and username == 'jeff':
            print("Login successful")
            func()
        else:
            print("login error!")
    return wrapper
@auth
def index():
    print("Welcome to China")
index()

  这里有一个登录的装饰器,当我们需要使函数中认证的信息存放在多种途径,并且再认证前确认认证信息,那么我们这个函数主体就需要加入一个参数存放认证途径,并且装饰器也需要传递参数,这个时候,我们把函数改为

def auth(filetype):
    def auth2(func):
        def wrapper(*args,**kwargs):
            if filetype == "file":
                username=input("Please input your username:")
                passwd=input("Please input your password:")
                if passwd == '123' and username == 'jeff':
                    print("Login successful")
                    func()
                else:
                    print("login error!")
            if filetype == 'SQL':
                print("No SQL")
        return wrapper
    return auth2
@auth(filetype='file')  
def index():
    print("welcome")
index()

  @auth(filetype='file') 将filetype参数传进auth的参数,并且运行auth返回auth2的地址,函数等同运行index=auth2(index),并且附带了外层filetype的参数,auth2(index)返回wrapper后执行wrapper,判断filetype,然后登陆。

  这样就是的参数传进了装饰器内部。这就是有参装饰器。

  当一个函数有多个装饰器时,

@ccc
@bbb
@aaa
def func()
    pass
func=ccc(bbb(aaa(func)))

迭代器

  在了解迭代器之前,首先要知道可迭代对象的概念,在python中可以调用__iter__()对象那就是可迭代对象,可以调用__next__()就是一个迭代器,__next__()用于迭代器取值。

  当next超出迭代器的范围时,python解释器会提示stopiteration,可以使用以下方式解决。

try:
    pass
expect StopIteration:
    break

  或者我们还可以使用for循环遍历迭代器,for循环其实就是将对象转化为迭代器再遍历,并且自动完成不会提示stopiteration。

  迭代器的优缺点:

  优点:

  迭代器可以遍历那些没有索引的对象,

  迭代器是惰性计算,每next一次就出一个值,这样更节省内存空间

  缺点:

  在运行完以前无法获取迭代器的长度,没有列表灵活

  只能往后取值,不能倒着取值

  可以使用内置函数isinstance来判断是否可迭代。

from collections import Iterable,Iterator
isinstance(*,iterable)
isinstance(*,iterator)

生成器

  函数体中有yield就是一个生成器。

  生成器的本质是一个迭代器,所以迭代器也适用与生成器。

  yield与return不同的是,return返回第一个值(元组也是一个整体)函数就结束了,但是yield可以返回多个值,在生成器函数中,每次执行到yield函数就暂停了,需要使用next去触发执行下一步。

协程函数

def eater(name):
    print('%s start to eat food'%name)
    while True:
        food=yield
        print('%s get %s ,to start eat'%(name,food))
    print('done')
e=eater('xx')
next(e)
e.send('egg')  
e.send('food')

  先定义一个协程函数,将yield作为参数赋值给food,next()协程函数就是初始化此函数,将函数运行到yield处停止住,然后使用send方法将值传给变量food,并同时执行一次next()。

  也就是说yield如果是表达式形式,执行前必定先next(),send与next当可以让函数在上一次暂停的位置继续运行,但是只有send可以在触发运行前给yield传一个值

  总结一下yield的功能,1.相当于将__iter__和__next__方法封装到函数内部,2.与return相比,yield可返回多次值,3.函数暂停已经继续运行的状态是通过yield保存的。

阅读(853) 评论(0)