Python初探第二篇-装饰器和迭代器,生成器

Posted ifyoushuai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python初探第二篇-装饰器和迭代器,生成器相关的知识,希望对你有一定的参考价值。

一,装饰器

  1,概念

  装饰器就是给已有的模块添加新的功能,如登录验证功能,运行时间功能等。本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
  强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
  装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

  2,理论基础

  要想实现装饰器的功能,我们需要三个理论基础:函数闭包+函数嵌套+高阶函数。我们通过为如下模块加入统计运行时间的装饰器来讲解如何使用

import time
def test_func():
    for i in range(5):
        time.sleep(0.5)

  3,推导

  首先我们知道要知道函数的运行时间,只需要在函数前后加上当前时间,通过差值就能计算出来。因此我们可以定义一个模块,并传入所求的函数的函数地址,即高阶函数。

  模块中包含此函数的调用和统计时间的功能

import time

def test_func():
    for i in range(5):
        time.sleep(0.5)

def decorate(func):
    start_time = time.time()
    func()
    end_time = time.time()
    print(end_time-start_time)

decorate(test_func)   #2.5s

  这样就实现了统计时间的功能,但是却修改了函数的调用逻辑,因此进一步思考,我们可以在装饰器函数内定义函数,并在此函数内调用被统计函数,即函数嵌套,并返回

       代码 如下:

import time
def test_func():
    for i in range(5):
        time.sleep(0.5)
def decorate(func):
    def count_time():
        start_time = time.time()
        func()
        end_time = time.time()
        print(end_time-start_time)
    return count_time
test_func = decorate(test_func)
test_func()

而python给我们提供了装饰器语法:

import time

def decorate(func):
    def count_time():
        start_time = time.time()
        func()
        end_time=time.time()
        print(end_time-start_time)
    return count_time

@decorate 
def test_func():
    for i in range(5):
        time.sleep(0.5)

test_func()

 上面就实现了一个简单的装饰器,可根据需求来增加它的功能,如传入参数,返回值等。

 

二,迭代器

  1,概念

  迭代器(iteretor)是一种遍历容器所有或者部分元素的方法,相当于一个复杂的指针,能够遍历复杂的数据结构,一个容器也应该提供它自己的迭代器。

  2,迭代器对象与可迭代对象

   迭代器对象:即对象能够提供遍历它的方法,像是迭代器的一种具体表现,在Python中迭代器对象能够提供__iter__和__next__方法来得到容器中下一个元素的值。

   可迭代对象:即对象提供__iter__方法,使用该方法后得到迭代器对象,如字符串,列表元组

li=[1,2,3,4,5]
li=li.__iter__()  # 可迭代对象转化成迭代器对象
print(li.__next__())  # 1

  3,使用方法  

dic = {"a": 1, "e": 4, "b": 2, "c": 3, "d": 4}
iter_dic = dic.__iter__()
# while True:
try:
    print(next(iter_dic))   #"a" "e" "b".....
except StopIteration:     #需要手动捕捉异常
    break

  而我们可以借助Python中强大的for循环机制来循环遍历容器

  4,for循环

#基于for循环,我们可以完全不再依赖索引去取值了
dic = {a:1,b:2,c:3}
for k in dic:
    print(dic[k])

#for循环的工作原理
#1:执行in后对象的dic.__iter__()方法,迭代器对象.__iter,返回对象本身。得到一个迭代器对象iter_dic
#2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
#3: 重复过程2,直到捕捉到异常StopIteration,结束循环

 三,生成器

  Python使用生成器能够实现延时操作,何谓延时操作,即需要结果时就产生结果,不需要时就不产生。提供生成器对象有两种方式:

  1,生成器函数:和常规的函数定义一样只不过不用return,而是使用yield来返回结果。一次只返回一个结果,在每个结果中间,挂起函数状态,以便下次继续返回。

  2,生成器表达式:生成一个生成器对象,按需产生结果,就是迭代的时候产生具体的值。

 

    1,生成器函数  

def gensquares(n):
    for i in range(n):
        yield i ** 2


obj = gensquares(5)
print(obj)  # <generator object gensquares at 0x00000000021E55C8>
print(next(obj))  # 0
print(next(obj))  # 1
print(next(obj))  # 4

  2,生成器表达式

li = []
for i in range(5):
    name = "name%d" % i
    li.append(name)
print(li)  # [‘name0‘, ‘name1‘, ‘name2‘, ‘name3‘, ‘name4‘]
# 列表推导
li = ["name%d" % i for i in range(5)]
print(li)  # [‘name0‘, ‘name1‘, ‘name2‘, ‘name3‘, ‘name4‘]
# 简洁了许多

# 生成器表达式
gens = ("name%d" % i for i in range(5))
print(gens)  # <generator object <genexpr> at 0x00000000028655C8>
print(next(gens))  # name0
print(next(gens))  # name1
print(next(gens))  # name2
#生成器对象就是迭代器对象

     使用生成器的好处数据不会直接加载到内存,在数据量很大的情况下作用很大。比如使用内置函数如下

#print(sum([i for i in range(100000000)])) #提示计算机内存不足,程序崩溃
print(sum((i for i in range(1000000000)))) #程正常运行

    注意事项:生成器对象是一种迭代器对象,它们都只能遍历一次,而可迭代对象可以多次遍历。

 




以上是关于Python初探第二篇-装饰器和迭代器,生成器的主要内容,如果未能解决你的问题,请参考以下文章

Python之装饰器迭代器和生成器

Python之迭代器生成器装饰器和递归

Python中的迭代器和生成器,以及装饰

python 双层装饰器格式化模块迭代器和生成器

迭代器生成器装饰器和标准库

模块调用,datetime,time,logging,递归,双层装饰器, json,pickle迭代器和生成器