上篇文章将了python多态,类属性等知识,这篇文章了解一下python的三器一包:迭代器、生成器、装饰器和闭包
Python的迭代器是一个重要的概念,特别是在处理序列数据和流数据时。迭代器是一种可以逐一遍历集合中所有元素的对象。
迭代器是实现了__iter__()
和__next__()
方法的对象。
__iter__()
: 这个方法返回迭代器对象本身。它在一个对象被迭代时会被自动调用,可以在循环或其他迭代环境中使用。__next__()
: 这个方法返回迭代中的下一个值。当序列遍历结束时,它会引发StopIteration
异常,通知迭代终止。在Python中,有两种与迭代有关的对象类型:可迭代对象和迭代器。
__iter__()
方法。
__next__()
时返回序列中的下一个值。迭代器对象实现了__iter__()
和__next__()
方法。
可以通过实现__iter__()
和__next__()
方法来手动创建一个迭代器。也可以通过iter()
函数将一个可迭代对象转换为迭代器。
# 自定义迭代器示例
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.data):
value = self.data[self.index]
self.index += 1
return value
else:
raise StopIteration
# 使用迭代器
my_iter = MyIterator([1, 2, 3])
for item in my_iter:
print(item)
python提供了一些内置函数来处理迭代器:
iter()
: 返回一个迭代器对象。对于可迭代对象,iter()
函数将其转换为迭代器。next()
: 通过调用迭代器的__next__()
方法来获取下一个元素。如果没有元素可返回,则会引发StopIteration
异常。#示例
numbers = [1, 2, 3]
iterator = iter(numbers)
print(next(iterator)) # 输出: 1
print(next(iterator)) # 输出: 2
print(next(iterator)) # 输出: 3
生成器是一种特殊的迭代器,它能够在需要时生成值,从而使得处理大型数据集或流数据变得更加高效。生成器通过使用 yield
关键字创建,并且具有延迟计算的特性,即惰性求值,只有在迭代时才会生成值。下面详细介绍生成器的相关概念和使用方法。
生成器(Generator) 是一种函数,它在每次调用时都会生成一个值,并在其 yield
语句的地方暂停执行,下一次迭代从暂停的位置继续。与普通函数不同,生成器函数在执行完所有 yield
语句后会自动退出。
生成器的关键特性包括:
生成器通过定义一个包含 yield
语句的函数来创建。yield
会暂停函数的执行并返回一个值,当生成器的 __next__()
方法被调用时,函数会从暂停处继续执行。
# 生成器函数示例
def my_generator():
print("First yield")
yield 1
print("Second yield")
yield 2
print("Third yield")
yield 3
# 使用生成器
gen = my_generator()
print(next(gen)) # 输出: First yield \n 1
print(next(gen)) # 输出: Second yield \n 2
print(next(gen)) # 输出: Third yield \n 3
python 提供了一种简洁的生成器定义方式,称为 生成器表达式。生成器表达式类似于列表推导式,但返回的是一个生成器对象,而不是一个列表。
# 生成器表达式示例
gen_expr = (x * x for x in range(5))
for value in gen_expr:
print(value)
在上面的示例中,gen_expr
是一个生成器,它在每次迭代时按需生成平方数。
生成器相比于普通函数和数据结构有许多优点:
除了使用 next()
函数来迭代生成器,还可以通过以下方式控制生成器:
send(value)
: 向生成器发送一个值,并暂停生成器的当前位置恢复执行。close()
: 终止生成器,生成器在下一次调用 __next__()
或 send()
时会引发 StopIteration
异常。throw(type, value=None, traceback=None)
: 在生成器中引发指定的异常,生成器可以捕获这个异常,并决定是继续还是终止。def controlled_generator():
while True:
value = yield
if value is None:
break
print(f'Received: {value}')
gen = controlled_generator()
next(gen) # 初始化生成器
gen.send('Hello') # 输出: Received: Hello
gen.send('World') # 输出: Received: World
gen.close() # 关闭生成器
生成器在Python中有许多实际应用,以下是一些常见的场景:
特性 | 生成器 | 列表 |
---|---|---|
内存使用 | 按需生成,节省内存 | 一次性加载所有元素,占用大量内存 |
执行方式 | 惰性求值,逐步生成 | 立即求值,一次性生成所有元素 |
适用场景 | 大数据集、流数据 | 小数据集,频繁访问元素 |
代码复杂度 | 简洁,适合管道处理 | 简单明了,适合频繁访问 |
通过生成器,可以使Python程序在处理大规模数据时更加高效,特别是在内存受限或需要流式处理的场景下。生成器不仅提供了强大的功能,还保持了代码的简洁和可维护性。
python的装饰器是一个强大的特性,允许你以优雅的方式修改函数或类的行为。装饰器可以用来插入额外的功能、修改函数行为,甚至是对函数进行包装而不直接修改其代码。
装饰器是一个函数,接受另一个函数作为参数,返回一个新的函数。这个新的函数通常会在原函数的调用之前或之后执行额外的代码。装饰器本质上是一种“包装”机制,使得你可以在不修改原始函数代码的情况下,添加额外的功能。
示例:
def my_decorator(func):
def wrapper():
print("有些事情在调用方法之前发生")
func()
print("有些事情在调用方法之后发生")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
在该示例中:
my_decorator
是一个装饰器函数,它接受 func
作为参数。wrapper
函数在调用 func
之前和之后打印了一些信息。@my_decorator
是装饰器的应用方式,相当于 say_hello = my_decorator(say_hello)
。say_hello()
时,实际执行的是 wrapper
函数,其中包括了原始的 say_hello
函数的调用。装饰器也可以接受参数。要实现带参数的装饰器,你需要创建一个嵌套的装饰器函数:
def repeat(num_times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def say_hello():
print("Hello!")
say_hello()
在这个例子中:
repeat
是一个接受参数 num_times
的外部函数。decorator
是实际的装饰器函数。wrapper
是用来包装原函数的内部函数,它会根据 num_times
的值多次调用原函数。装饰器在实际编程中非常有用,常见的应用场景包括:
使用装饰器时,通常会改变原函数的一些元数据,如名称和文档字符串。可以使用 functools.wraps
来保留这些元数据
示例:
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("调用函数之前被执行")
result = func(*args, **kwargs)
print("调用函数之后被执行")
return result
return wrapper
@my_decorator
def say_hello():
"""Prints 'Hello!'"""
print("Hello!")
print(say_hello.__name__) # 输出 'say_hello'
print(say_hello.__doc__) # 输出 'Prints 'Hello!''
@wraps
装饰器帮助 wrapper
函数保留原函数的元数据(如名称和文档字符串)
装饰器是一种功能强大的工具,可以让你在不修改原始函数代码的情况下,添加额外的功能。理解装饰器的工作原理以及如何创建和使用它们,可以让你写出更加简洁、灵活和可维护的代码。
闭包是一个函数对象,它能记住并访问它所在的词法作用域中的变量,即使在该作用域已经结束时,仍然可以使用这些变量。换句话说,闭包是一种函数,可以捕获其外部环境的变量,使得这些变量即使超出了其正常的生命周期也能在函数内被访问。
闭包是由嵌套函数和自由变量构成的,闭包可以访问这些自由变量,即外部函数作用域中的变量,即使外部函数已经执行完毕。
一个闭包通常由三部分组成:
示例:
def outer_function(message):
def inner_function():
print(message)
return inner_function
closure_function = outer_function("Hello, Python!")
closure_function() # 输出: Hello, Python!
在这个例子中:
outer_function
是外部函数,它接受一个参数 message
。inner_function
是嵌套在 outer_function
中的内部函数,它使用了外部函数的变量 message
。outer_function
返回 inner_function
时,message
的值仍然被保留并可以在之后调用 closure_function()
时使用,即使 outer_function
已经执行完毕。在上述示例中,虽然 outer_function
已经执行结束,但返回的 inner_function
依然“记住”了 message
变量的值。这种机制就是闭包的重要特性,函数会保存它们所在的词法作用域中的变量,使得这些变量可以在函数执行后依然有效。python中的闭包通过函数对象的 __closure__
属性来实现,这个属性包含了对外部作用域变量的引用。
示例:
def outer_function(message):
def inner_function():
print(message)
return inner_function
closure_function = outer_function("Hello, Python!")
print(closure_function.__closure__) # 输出闭包中的自由变量
print(closure_function.__closure__[0].cell_contents) # 输出自由变量的值 "Hello, Python!"
闭包在以下场景中非常有用:
闭包虽然强大,但也有一些需要注意的地方:
nonlocal
关键字。通常情况下,闭包只能访问外部变量,但不能修改它们。如果需要修改外部函数中的变量,必须使用 nonlocal
关键字:
示例:
def outer_function():
count = 0
def inner_function():
nonlocal count # 使用nonlocal声明
count += 1
print(count)
return inner_function
closure_function = outer_function()
closure_function() # 输出 1
closure_function() # 输出 2
在这个例子中,nonlocal
允许 inner_function
修改 outer_function
中的 count
变量。
python的闭包是一种函数对象,它能够捕获并“记住”外部函数作用域中的自由变量,使得这些变量在外部函数执行结束后依然可用。闭包在许多高级编程场景中非常有用,比如装饰器、回调函数和数据隐藏等。
该篇文章主要讲了python的三器一包,迭代器、生成器、装饰器和闭包,每个知识点都有各自的用途,相信大家都能通过这篇文章体会到其中的差异点,欢迎提出宝贵的意见和建议!!