Python高阶:三个神器 - 迭代器、生成器与装饰器

深入理解Python三大利器

1 概述

1.1 案例介绍

在 Python 编程中,迭代器(Iterator)和生成器(Generator)是两个非常重要的概念,它们为处理序列数据提供了高效、灵活且优雅的方式。迭代器允许我们逐个访问容器中的元素,而生成器则可以按需生成数据,避免一次性生成大量数据占用过多内存。理解和掌握迭代器与生成器对于编写高效、简洁且易于维护的 Python 代码至关重要。 而装饰器(decorators)是函数式编程中的一种强大功能,用来在不改变原函数代码的情况下,增强或修改函数的行为。

1.2 适用对象

  • 个人开发者
  • 高校学生

1.3 案例时间

本案例总时长预计30分钟。

1.4 案例流程

image.png 说明: ① 登录华为云注册开发者空间,进入云主机,打开CodeArts IDE for Python创建工程; ② 编写代码运行。

1.5 资源总览

本案例预计花费总计0元。 | 资源名称 | 规格 | 单价(元) | 时长(分钟) | |-------------------|------------------------------------------|----------------|------------------| |开发者空间-云主机| 2vCPUs | 4GB X86 CodeArts IDE for Python| 免费 |30|

2 准备开发环境

2.1 配置云主机并进入

参考“10分钟玩转云主机” 案例介绍中“2.2 申请云主机”章节内容完成华为开发者空间云主机申请与配置,配置云主机建议:“CPU架构”选择“X86”,“操作系统”选择“Ubuntu”。 image.png 然后点击“进入桌面”进入云主机。 image.png

2.2 使用CodeArts IDE创建工程

参考“初识云主机:CodeArts IDE入门”案例介绍“3.1 新建工程”章节新建工程。 新建的工程包含如下三个目录文件部分: | 目录文件 | 说明 | |--------------------------|------------------------------------------| |.arts |CodeArts的配置文件| |venv |虚拟环境| |main.py|默认生成的入口文件|

image.png

3 三个神器

3.1 迭代器

迭代器是一个表示数据流的对象,它实现了迭代器协议,该协议包含两个函数__iter__()和__next__()。任何包含这两个函数的对象都可以被视为迭代器,用于在遍历容器(如列表、元组、字典等)时提供逐个元素的访问方式,而无需暴露容器的内部结构。 下面练习以帮助我们掌握Python这门编程语言中迭代器创建及使用的相关知识。

3.1.1 迭代

在 Python 中,迭代是指通过逐步访问一个容器(如列表、元组、字典等)或可迭代对象(如生成器、文件对象等)中的每个元素的过程。 迭代让你能够依次处理容器中的每一个元素,而不需要显式地知道它们的索引或数量。迭代是 Python 处理集合、序列和其他可遍历数据结构的核心机制。 代码示例:

# 使用 for 循环对数据做迭代:
List = [1,2,3]
str_ = "py3"
Tuple = (9,8,7)
Dict = {"a":1,"b":2,"c":3}
Set = {"A","B","C"}
for i in zip(List,str_,Tuple,Dict,Set):
  print(i)
3.1.2 可迭代对象

在 Python 中,我们把能够进行迭代读取数据供我们使用的对象称之为可迭代对象(Iterable)。常见的可迭代对象包括列表、字符串、元组、字典、集合、文件对象(open(xxx))、实现了迭代协议的对象等。 使用 Iterable 来判断数据是否是可迭代对象。 代码示例:

# 使用 Iterable 来判断数据是否是可迭代对象
from collections.abc import Iterable
list=[1,2,3]
str='hello python'
tuple=(1,2,3)
dict ={'name':'qx','age':18}
set= {1,2,3}
print("list:",isinstance(list,Iterable))
print("str:",isinstance(str,Iterable))
print("tuple:",isinstance(tuple,Iterable))
print("dict:",isinstance(dict,Iterable))
print("set:",isinstance(set,Iterable))
print("num:",isinstance(1,Iterable))

自定义实现一个可迭代对象。 代码示例:

from collections.abc import Iterable
class Iter_obj(object):
 """自定义一个类,实现__iter__函数"""
 def __init__(self, value):
  self.value = value
 def __iter__(self):
  self.index = 3
  return iter(self.value[:self.index])
# 实例化
L = Iter_obj([1, 2, 3, 4, 5, 6])
# 校验是否是可迭代对象
print(isinstance(L, Iterable))
for i in L:
 print(i)
3.1.3 迭代器

迭代器是一个表示数据流的对象,它实现了迭代器协议,该协议包含两个函数__iter__()和__next__()。任何包含这两个函数的对象都可以被视为迭代器,用于在遍历容器(如列表、元组、字典等)时提供逐个元素的访问方式,而无需暴露容器的内部结构。 代码示例:

# 使用 Iterator来判断数据是否是迭代器
from collections.abc import Iterator
print("list:",isinstance(list,Iterator))
print("str:",isinstance(str,Iterator))
print("tuple:",isinstance(tuple,Iterator))
print("dict:",isinstance(dict,Iterator))
print("set:",isinstance(set,Iterator))
print("num:",isinstance(1,Iterator))
# 可迭代对象不一定是迭代器,使用内置函数iter()创建迭代器
l = iter([1,2,3])
d = iter({"a":1,"b":2})
print(isinstance(l,Iterator))
print(isinstance(d,Iterator))
3.1.4 迭代器的使用

使用for循环遍历。使用for循环来遍历迭代器,for循环会自动处理StopIteration异常,使代码更加简洁和安全。 代码示例:

# 使用for循环输出迭代器数据
l = [1,2,3]
l = iter(l)
for i in l:
 print(i)

创建了迭代器,可以使用next()函数逐个获取元素。每次调用next()函数,迭代器就会返回下一个元素,直到没有更多元素时抛出StopIteration异常。 代码示例:

# 使用next()函数获取元素
d = iter({"a":1,"b":2})
print(next(d))
print(next(d))
3.1.5 实现一个迭代器

代码示例:

# 实现一个自定义的迭代器
from collections.abc import Iterable
class IterObj:
 def __init__(self, value):
  self.value = value
  self.i = 0

 def __iter__(self):
  return iter(self.value)

 def __next__(self):
  while self.i < len(self.value):
   v = self.value[self.i]
   self.i += 1
   return v
 # 此处可以增加 StopIteration
ite = IterObj([1, 2, 3, 4, 5])
print(isinstance(ite, Iterable))
print(next(ite))

3.2 生成器

生成器(Generator)是一种特殊的迭代器,它使用更简洁的语法来创建迭代器。 生成器函数(使用yield语句的函数)或生成器表达式可以用来创建生成器对象,它能够在需要时生成数据,而不是一次性生成所有数据并存储在内存中。

3.2.1 生成器表达式

生成器表达式是一种简洁的创建生成器的方式,类似于列表推导式,但使用圆括号而不是方括号。 代码示例:

# 下面的生成器表达式可以生成 1 到 5 的平方数
gen_expr = (i**2 for i in range(1, 6))
print(type(gen_expr))
#使用next()函数取值,若超出取值范围,则会抛出stopIteration异常。
print(next(gen_expr))
print(next(gen_expr))
print(next(gen_expr))
print(next(gen_expr))
3.2.2 生成器函数

生成器函数是一种包含yield语句的函数。当调用生成器函数时,它返回一个生成器对象,而不是立即执行函数体中的代码。 代码示例:

# 通过 yield 创建生成器函数
def fib(n):
 current = 0
 num1, num2 = 0, 1
 while current < n:
    num = num1
    num1, num2 = num2, num1+num2
    current += 1
    yield num
 return 'done'
g=fib(5)
while True:
 try:
    x = next(g)
    print("value:%d"%x)
 except StopIteration as e:
    print("生成器返回值:%s"%e.value)
    break
3.2.3 Send函数

除了使用next()函数以外,还可以使用send()函数唤醒生成器,相比于next()函数,send()函数在唤醒生成器时还可以向断点处传入一个数据。 代码示例:

# finally的代码块无论是否有异常都会执行。
def gen():
 i = 0
 while i<5:
  temp = yield i
  print(temp)
  i+=1
f = gen()
print(next(f))
f.send('haha')
print(next(f))

3.3 装饰器

在Python中,装饰器(Decorators)是函数式编程中的一种强大功能,用来在不改变原函数代码的情况下,增强或修改函数的行为。装饰器常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

3.3.1 闭包

在一个内部函数中,对外部作用域的变量进行引用,并且外部函数的返回值为内部函数,那么内部函数就叫做闭包(Closure)。闭包有三个特点:必须有一个内嵌函数。内嵌函数必须引用外部函数中的变量。外部函数的返回值必须是内嵌函数。 代码示例:

def outer_func(x):
    # 这是外部函数
    def inner_func(y):
        # 这是内嵌函数,它可以访问外部函数的变量x
        return x + y
    return inner_func

# 创建闭包
my_closure = outer_func(10)
# 使用闭包
print(my_closure(5))  # 输出: 15
3.3.2 函数装饰器

实现一个装饰器,定义装饰器函数,功能用于计算程序运行时间,由于不清楚所装饰的函数的参数,通过不定长参数实现一个通用的装饰器。 代码示例:

# 定义装饰器函数
import time
def func(f):
 def inner(*args, **kwargs): # 不定长参数
  start_time = time.time()
  f(*args, **kwargs)
  end_time = time.time()
  print('耗时:%s 秒' % (end_time - start_time))
 return inner

#定义被装饰函数
@func
def test():
 time.sleep(2)
test()   
3.3.3 类装饰器

我们创建一个类装饰器,通过类的__init__ 函数接收外部参数,__call__函数处理装饰逻辑。 代码示例:

class Tiga():
    def __init__(self, f):
        self.f = f
    def __call__(self, *args, **kwargs):
        print("叮~,变身")
        self.f(*args, **kwargs)
        print("光之巨人")
    def Red(self, f):
        def wrapper(*args, **kwargs):
            print("切换战士形态:力量+100")
            f(*args, **kwargs)
        return wrapper
    @classmethod
    def Blue(cls, f):
        def wrapper(*args, **kwargs):
            print("切换刺客形态:敏捷+100")
            f(*args, **kwargs)
        return wrapper
@Tiga
def func():
    print("化身成为光!")

func()
@Tiga.Blue
def fight1():
    print("速度很快,但是没有破防")
fight1()

@func.Red
def fight2():
    print("使出一记重拳,但是没打中")
fight2()  
3.3.4 多个装饰器

我们尝试一次设置多个装饰器函数,增加多种功能,然后通过语法糖的方式(@函数名)装饰到被装饰函数上。 代码示例:

# 定义多个功能的装饰器。
def Tiga(func):
 print("给我力量吧,Tiga")
 def tiga():
  func()
  print("获得 Tiga 的力量")
 return tiga
def Dyna(func):
 print("给我力量吧,Dyna")
 def dyna():
  func()
  print("获得 Dyna 的力量")
 return dyna
def Gaia(func):
 print("给我力量吧,Gaia")
 def gaia():
  func()
  print("获得 Gaia 的力量")
 return gaia
@Tiga
@Dyna
@Gaia
def Z():
 print("受死吧,五帝王")
Z()           
3.3.5 解除装饰器

在使用装饰器后,如果需要解除当前装饰器,则在被装饰函数中调用__wrapped__函数,被装饰函数只使用之前函数的功能。 代码示例:

from functools import wraps

def light(func):
 print("获得神光棒 x1")
 @wraps(func)
 def tiga():
  func()
  print("叮~,\n 我是光之巨人")
 return tiga

@light
def person():
 print("我是某胜利队队员大骨")
DaGu = person.__wrapped__
DaGu()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值