Python - 可迭代,迭代器,生成器,装饰器

打印 上一主题 下一主题

主题 655|帖子 655|积分 1965

一.可迭代对象

可迭代对象是指实现了 __iter__() 方法的对象。__iter__() 方法返回一个迭代器对象。常见的可迭代对象包摆列表、元组、字符串、字典和集合等。
  1. s = "world"
  2. s1 = [1, 2, 3, 4, 5]
  3. s2 = (1, 2, 3, 4, 5)
  4. s3 = {"name": "猫"}
  5. s4 = {1, 2, 3, 4, 5}
  6. print(isinstance(s, Iterable), isinstance(s1, Iterable), isinstance(s2, Iterable), isinstance(s3, Iterable), isinstance(s4, Iterable))   
  7. # 结果:True True True True True
复制代码
分析:在这段代码中,我们使用了 isinstance() 函数来查抄差别的对象是否是可迭代对象,返回结果均为True,阐明列表、元组、字符串、字典和集合都是可迭代对象
二.迭代器

迭代器是指实现了 __iter__() 和 __next__() 方法的对象。__next__() 方法返回下一个元素,假如没有更多元素则抛出 StopIteration 异常。
类 MyDatas 的迭代器实现

  1. class MyDatas:
  2.     def __init__(self, n):
  3.         """
  4.         初始化方法,创建一个包含从1到n的整数列表,并初始化当前索引为0
  5.         :param n: 整数,表示列表的最大值
  6.         """
  7.         self.datas = [i for i in range(1, n + 1)]  # 创建包含从1到n的整数列表
  8.         self.current_index = 0  # 初始化当前索引为0
  9.     def __iter__(self):
  10.         """
  11.         返回迭代器对象自身
  12.         :return: 返回self,即当前对象
  13.         """
  14.         return self
  15.     def __next__(self):
  16.         """
  17.         返回下一个元素,如果当前索引超出列表范围,抛出IndexError异常
  18.         :return: 返回当前元素
  19.         """
  20.         if self.current_index >= len(self.datas):  # 检查当前索引是否超出列表范围
  21.             raise IndexError  # 抛出IndexError异常
  22.         else:
  23.             current = self.datas[self.current_index]  # 获取当前元素
  24.             self.current_index += 1  # 将当前索引加1
  25.             return current  # 返回当前元素
  26. # 假设md是一个MyDatas对象,例如 md = MyDatas(5)
  27. while True:
  28.     try:
  29.         for s in md:  # 尝试遍历md对象
  30.             print(s)  # 打印当前元素
  31.     except IndexError as e:  # 捕获IndexError异常
  32.         print("超出范围", e)  # 打印错误信息
  33.         break  # 退出循环
复制代码
分析:
__init__ 方法
初始化一个包含从1到n的整数列表 self.datas。
初始化当前索引 self.current_index 为0。
__iter__ 方法
返回迭代器对象自身,即 self。这使得 MyDatas 实例可以被用作迭代器。
__next__ 方法
查抄当前索引是否超出列表范围,假如超出则抛出 IndexError 异常。
否则,返回当前元素并将当前索引加1。
  1. while True:
  2.     try:
  3.         for s in md:  # 尝试遍历md对象
  4.             print(s)  # 打印当前元素
  5.     except IndexError as e:  # 捕获IndexError异常
  6.         print("超出范围", e)  # 打印错误信息
  7.         break  # 退出循环
复制代码
分析:
while True 循环不断尝试遍历 md 对象。
for s in md 使用 for 循环遍历 md 对象,这会调用 md 的 __iter__() 方法获取迭代器,并调用 __next__() 方法获取下一个元素。
假如 __next__() 方法抛出 IndexError 异常,捕获该异常并打印错误信息,然退却出循环。
总结:
迭代器:实现了 __iter__() 和 __next__() 方法的对象。
自定义迭代器:通过定义类并实现 __iter__() 和 __next__() 方法来创建自定义迭代器。
迭代器的使用:通过 for 循环或其他迭代方式使用迭代器,自动调用 __iter__() 和 __next__() 方法。
异常处理:在迭代过程中处理可能抛出的异常(如 IndexError)。
三.生成器

生成器是Python中一种特殊的迭代器,它使用 yield 关键字来产生值。生成器函数在调用时返回一个生成器对象,每次调用 next() 时,生成器函数会从前次 yield 的位置继续执行,直到遇到下一个 yield 或函数竣事。
生成器的基本概念

生成器函数使用 yield 关键字来产生值,而不是 return。每次调用 next() 时,生成器函数会从前次 yield 的位置继续执行,直到遇到下一个 yield 或函数竣事。
生成器函数

  1. def my_generator():
  2.     yield 1
  3.     yield 2
  4.     yield 3
  5. gen = my_generator()
  6. for item in gen:
  7.     print(item)
复制代码
分析:在这个例子中,my_generator 是一个生成器函数,它使用 yield 关键字来产生值。调用 my_generator() 返回一个生成器对象 gen,我们可以使用 for 循环来遍历它。
生成器表达式

  1. gen = (x for x in range(1, 4))
  2. for item in gen:
  3.     print(item)
复制代码
分析:(x for x in range(1, 4)) 是一个生成器表达式,它返回一个生成器对象 gen,我们可以使用 for 循环来遍历它。
上风

结合 sys.getsizeof() 函数,我们可以更直观地理解生成器在内存使用上的上风。sys.getsizeof() 函数用于获取对象的内存占用大小(以字节为单元)。
  1. # 创建一个包含100万个整数的列表
  2. list_data = [i for i in range(1000000)]
  3. # 创建一个生成器表达式,生成100万个整数
  4. gen_data = (i for i in range(1000000))
  5. # 打印列表和生成器的内存占用大小
  6. print(list_data.__sizeof__())
  7. print(gen_data.__sizeof__())
  8. # 结果:8448712  176
复制代码
分析:通过比较列表和生成器的内存占用大小,我们可以直观地看到生成器在处理大数据集时的内存上风。生成器非常适合处理大数据集,因为它不会一次性将全部数据加载到内存中,从而节省内存资源。
四.装饰器

装饰器是一种用于修改函数或方法行为的高阶函数。装饰器本质上是一个返回函数的函数,它可以在不修改原函数代码的情况下,增加额外的功能。
  1. # 装饰器
  2. def cost_time(f):
  3.     def calc():
  4.         start = time.time()
  5.         f()
  6.         print(f"{f.__name__}的时间开销是{time.time() - start}")
  7.     return calc
  8. data = [random.randint(1, 10000) for i in range(10000)]
  9. datas = data.copy()
  10. @cost_time
  11. def my_sort1():
  12.     data.sort()
  13.     print(data)
  14. # my_sort1 = cost_time(my_sort1)
  15. my_sort1()
  16. @cost_time
  17. def my_sort2():
  18.     new_datas = sorted(datas, reverse=False)
  19.     print(new_datas)
  20. # my_sort2 = cost_time(my_sort2)
  21. my_sort2()
复制代码
装饰器 cost_time

  1. def cost_time(f):
  2.     def calc():
  3.         start = time.time()
  4.         f()
  5.         print(f"{f.__name__}的时间开销是{time.time() - start}")
  6.     return calc
复制代码
cost_time 是一个装饰器函数,它接受一个函数 f 作为参数。
在 cost_time 内部定义了一个嵌套函数 calc,这个函数用于测量 f 的执行时间。
start = time.time():纪录函数开始执行的时间。
f():调用原函数 f。
print(f"{f.__name__}的时间开销是{time.time() - start}"):打印函数 f 的名称和执行时间。
cost_time 返回嵌套函数 calc,如许当装饰器应用到一个函数时,实际上是返回了一个新的函数 calc,这个函数包含了原函数 f 的调用和时间测量逻辑
函数 my_sort1 和 my_sort2

  1. @cost_time
  2. def my_sort1():
  3.     data.sort()
  4.     print(data)
  5. # my_sort1 = cost_time(my_sort1)
  6. my_sort1()
  7. @cost_time
  8. def my_sort2():
  9.     new_datas = sorted(datas, reverse=False)
  10.     print(new_datas)
  11. # my_sort2 = cost_time(my_sort2)
  12. my_sort2()
复制代码
my_sort1 和 my_sort2 是两个用于排序的函数。
@cost_time 语法是装饰器的应用,相当于 my_sort1 = cost_time(my_sort1) 和 my_sort2 = cost_time(my_sort2)。
这表示在调用 my_sort1 和 my_sort2 时,实际上是调用了 cost_time 返回的 calc 函数。
my_sort1 使用 list.sort() 方法对 data 进行原地排序。
my_sort2 使用 sorted() 函数对 datas 进行排序,并返回一个新的排序后的列表 new_datas。
总结
装饰器 cost_time 用于测量函数执行的时间开销。
my_sort1 和 my_sort2 分别使用差别的排序方法对数据进行排序。
通过装饰器,我们可以在不修改原函数代码的情况下,增加时间测量的功能。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

没腿的鸟

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表