迭代器,生成器,装饰器

断了今生、忘了曾经 提交于 2020-03-03 02:02:25

1.1迭代器
1.2生成器
1.3装饰器

迭代器

1. 迭代器定义

  1. 迭代是Python最强大的功能之一,是访问集合元素的一种方式
  2. 迭代器是一个可以记住遍历的位置的对象。
  3. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
  4. 迭代器有两个基本的方法:iter() 和 next()。
  5. 字符串,列表或元组对象都可用于创建迭代器:

2.可迭代对象

在Python世界里,一切皆对象。对象根据定义的维度,又可以分为各种不同的类型,比如:文件对象,字符串对象,列表对象。。。等等。
一句话:“实现了__iter__方法的对象就叫做可迭代对象”,__iter__方法的作用就是返回一个迭代器对象。
直观理解就是能用for循环进行迭代的对象就是可迭代对象。比如:字符串,列表,元祖,字典,集合等等,都是可迭代对象。

3.next()与iter():

next()返回迭代器的下一个项目
next语法:
next(iterator[,dafault])

iterator – 可迭代对象
default – 可选,用于设置在没有下一个元素时返回该默认值,如果不设置,又没有下一个元素则会触发 StopIteration 异常。

4.iter()函数用来生成迭代器

# 迭代器实现斐波那契数列
class Fib():
  def __init__(self,n):
    self.a = 0   # 第一个数
    self.b = 1    # 第二个数
    self.c = n    # 传过来的数
    # print(n)
    self.count = 0   # 用来记录访问的位置

  def __iter__(self):
    return self

  def __next__(self):
    if self.count < self.c:   # 用来记录的数不能大于传过来的数
      res = self.b   # res返给用户的值
      self.a,self.b = self.b,self.a+self.b   # 第一个,第二个赋值给第一个就等于第二个,第二个就等于本身加前面一个
      self.count += 1
      return res
    else:
      raise StopIteration   # 如果有异常就停止迭代


print(list(Fib(5)))
print(list(Fib(10)))
"""
打印结果
[1, 1, 2, 3, 5]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
"""

6.生成器和迭代器之间的区别
在使用生成器时,我们创建一个函数;在使用迭代器时,我们使用内置函数iter()和next()。 在生成器中,我们使用关键字‘yield’来每次生成/返回一个对象。 生成器中有多少‘yield’语句,你可以自定义。 每次‘yield’暂停循环时,生成器会保存本地变量的状态。而迭代器并不会使用局部变量,它只需要一个可迭代对象进行迭代。 使用类可以实现你自己的迭代器,但无法实现生成器。 生成器运行速度快,语法简洁,更简单。 迭代器更能节约内存。

生成器

生成器定义、简介
在python中,生成器是根据某种算法边循环边计算的一种机制。主要就是用于操作大量数据的时候,一般我们会将操作的数据读入内存中处理,可以计算机的内存是比较宝贵的资源,我认为的当要处理的数据超过内存四分之一的大小时就应该使用生成器。

生成器的作用

  1. 通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的。
  2. 而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
  3. 所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?
  4. 这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

特点

  1. 和传统的容器相比,生成器更节省内存。
  2. 延迟计算,在我们需要结果时就调用一下生成器的next()方法即可。
  3. 可迭代,你可以像遍历list一样,遍历生成器

生成器工作原理

  1. 生成器是这样一个函数,它记住上一次返回时在函数体中的位置。
  2. 对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。
  3. 生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造中的位置。
  4. 生成器是一个函数,而且函数的参数都会保留。
  5. 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的

在python中有两种方式创建生成器:生成器表达式 和 生成器函数。

生成器 和 普通函数的区别 ?
生成式函数和普通函数只有一个区别,普通函数使用return返回结果,而生成器函 数使用yield返回结果。
yield的特点在于,它并不是结束函数,而是在返回结果后将函数处于一种挂起状态,等待再次next函数的调用,然后从上次挂起的地方(yield)继续执行。
可迭代的数据类型
列表、元组、字典和集合都是可迭代的对象,可以从其中获得迭代器。
所有这些对象都可用iter()方法获取迭代器:
yield运行机制:
在Python中,yield就是这样的一个生成器。

  1. 当你问生成器要一个数时,生成器会执行,直至出现 yield 语句,生成器把yield 的参数给你,之后生成器就不会往下继续运行。
  2. 当你问他要下一个数时,他会从上次的状态开始运行,直至出现yield语句,把参数给你,之后停下。如此反复
  3. 在python中,当你定义一个函数,使用了yield关键字时,这个函数就是一个生成器
  4. 它的执行会和其他普通的函数有很多不同,函数返回的是一个对象,而不是你平常所用return语句那样,能得到结果值。如果想取得值,那得调用next()函数
  5. 每当调用一次迭代器的next函数,生成器函数运行到yield之处,返回yield后面的值且在这个地方暂停,所有的状态都会被保持住,直到下次next函数被调用,或者碰到异常循环退出。

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

# 用生成器实现斐波那契数列
def fib(max_num):   # max_num = fid(10)
  a,b = 0,1   # a定义为0,b定义为1
  while a < max_num:   # a<fid(10),才会执行
    yield b   # 相当于返回
    a,b = b,a+b   # 赋值

g = fib(10)   # 生成一个生成器
print(g.__next__())   # 第一次调用返回:1
print(list(g))   # 把剩下的元素变成列表 [1, 2, 3, 5, 8, 13, 21]
"""
1
[1, 2, 3, 5, 8, 13]
"""

装饰器

介绍:
装饰器(Decorators)是 Python 的一个重要部分。
简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。

装饰器的概念:

  1. 装饰器实际上就是一个函数
  2. 有2个特别之处,参数是一个函数。返回值是一个参数

装饰器的简单理解:

实际上就是为了给一个程序添加功能,但是该程序已经上线或者已被使用,
那么就不能大批量的修改源码,这样不现实,因此就产生了装饰器。
注意点:

  1. 不能修改被装饰的函数的源代码
  2. 不能修改被装饰的函数的调用方式

装饰器组成方式:
函数+实参高阶函数+返回值高阶函数+嵌套函数+语法堂 = 装饰器

有关高阶函数的理解:
把一个函数名当作实参传给另外一个函数(”实参高阶函数“)
返回值中包含函数名(”返回值高阶函数“)

嵌套函数的理解:
嵌套函数指的是在函数内部定义一个函数,而不是调用。

语法糖
写法:@xx ,一般写在函数的上方

装饰器实例

1. 使用高阶函数模拟装饰器:

import time
def times(func):
  start_time = time.time()
  func()
  print('函数执行时间为', time.time() - start_time)

def test():
  print('开始执行test')
  time.sleep(3)
  print('test执行结果')

times(test)

"""
开始执行test
test执行结果
函数执行时间为 3.0029656887054443
"""

2.计算运行时间装饰器:

import time
def times(func):  # func = test1
  def deco(*args,**kwargs):
    start_time = time.time()
    func(*args,**kwargs)    # func = test1  实际上对test1的调用
    stop_time = time.time()
    print("running time is %s"%(stop_time-start_time))
  return deco

@times
def test1():
  time.sleep(3)
  print('in the test1')

test1()

"""
in the test1
running
"""

3.装饰无参函数,示例代码如下:

# 计算时间装饰器
# 装饰器装饰的函数无参数
import time
def times(func):   # func指的就是test1
  def deco():
    start = time.time()
    print('---------',start)
    func()  # 这里就是对test1的调用
    stop = time.time()
    print('+++++++++++++++',stop)
    print(stop-start)
  return deco

@times
def test1():
  time.sleep(2)
  print('test111')
  time.sleep(2)
test1()
"""
--------- 1580555864.257956
test111
+++++++++++++++ 1580555868.2594745
4.001518487930298
"""

4.装饰有参函数,示例代码如下:

import time
def times(func):  # func = test
  def deco(*args,**kwargs):   # 添加可变参数*args,**kwargs
    start = time.time()
    func(*args,**kwargs)    # func = test 这里也一样,添加可变参数*args,**kwargs
    stop = time.time()
    print(start-stop)
  return deco

@times
def test(value): # test函数有两个参数value,正因为装饰器times装饰的函数test有参数value,因此在times中有了可变参数
  time.sleep(2)
  print('开始执行 %s'%(value+time.time()))

test(22)
"""
开始执行 1580556248.4975662
-2.000622510910034
"""

5.带参数的装饰器,示例代码如下:

# 带参数的装饰器
import time
def times(func):
  def out_time(func1):    # func = task
    def wrapper(*args,**kwargs):
      if func == 'task1':   # func == 'task1'的情况下,执行任务一
        start = time.time()
        func1(*args,**kwargs)
        stop = time.time()
        print('任务一 进行:',stop-start)
      elif func == 'task2':  # func == 'task2'的情况下,执行任务二
        func1(*args,**kwargs)
        print('任务二 执行:')
    return wrapper
  return out_time

@times(func='task1')
def task1():
  time.sleep(2)
  print('任务1')
@times(func='task2')
def task2():
  time.sleep(2)
  print('任务2')

task1()
task2()
"""
任务1
任务一 进行: 2.000582218170166
任务2
任务二 执行:
"""

装饰器使用场景
授权:装饰器能有助于检查某个人是否被授权去使用一个web应用的端点(endpoint)。它们被大量使用于Flask和Django web框架中
日志:在记录日志的地方添加装饰器
缓存:通过装饰器获取缓存中的值

闭包
定义:
如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内部的我们叫他内函数。那闭包就是,在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!