一、生成器与迭代器
1、生成器函数
生成器函数是一种特殊的函数,它使用yield语句来产生一个序列的值。与普通函数一样,生成器函数也可以接收参数并返回值,但它的执行方式与普通函数不同。生成器函数在每次调用时并不会立即执行,而是返回一个生成器对象,通过调用生成器对象的next()方法可以逐个获取生成器函数产生的值。
下面是一个简单的生成器函数的示例:
def my_generator():
yield 1
yield 2
yield 3
# 调用生成器函数,返回一个生成器对象
gen = my_generator()
# 调用生成器对象的next()方法获取生成器函数产生的值
print(next(gen)) # 输出1
print(next(gen)) # 输出2
print(next(gen)) # 输出3
生成器函数可以用于生成大量的数据,而不需要一次性将所有数据存储在内存中,这在处理大数据集时非常有用。下面是一个生成斐波那契数列的示例:
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# 调用生成器函数,返回一个生成器对象
gen = fibonacci()
# 使用for循环来遍历生成器对象获取斐波那契数列的值
for i in range(10):
print(next(gen))
生成器函数还可以接收外部传入的参数,这样可以根据不同的参数生成不同的序列。下面是一个根据传入参数生成指定范围内的偶数的示例:
def even_numbers(n):
for i in range(n):
if i % 2 == 0:
yield i
# 调用生成器函数,返回一个生成器对象
gen = even_numbers(10)
# 使用for循环来遍历生成器对象获取指定范围内的偶数
for num in gen:
print(num)
生成器函数的使用非常灵活,可以方便地生成各种各样的序列。在处理大量数据时,使用生成器函数可以大大节省内存空间,同时也能提高程序的运行效率。
2、yield关键字
yield是Python中的一个关键字,用于创建一个生成器函数。生成器函数在调用时,并不执行函数体中的代码,而是返回一个生成器对象。
生成器对象可以通过next()函数来逐步执行生成器函数中的代码,直到遇到yield关键字。遇到yield关键字时,生成器函数会暂停并返回yield后面的值,下次调用next()函数时,生成器函数会从上次暂停的地方继续执行。
以下是一个简单的示例,演示了如何使用yield关键字创建一个生成器函数:
def generator():
yield 1
yield 2
yield 3
gen = generator()
print(next(gen)) # 输出:1
print(next(gen)) # 输出:2
print(next(gen)) # 输出:3
在这个例子中,generator函数包含了三个yield语句,每次调用next()函数时,生成器函数会返回一个yield关键字后面的值。可以通过多次调用next()函数来逐步获取生成器函数中的值。
另外一个常见的用法是使用生成器函数来实现一个迭代器。迭代器是一个可以遍历数据的对象,通过定义一个生成器函数,可以轻松创建一个迭代器对象。
以下是一个示例,演示了如何使用yield关键字来实现一个简单的迭代器对象:
class Counter:
def __init__(self, start, end):
self.start = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.start > self.end:
raise StopIteration
current = self.start
self.start += 1
return current
counter = Counter(1, 5)
for num in counter:
print(num) # 输出:1 2 3 4 5
在这个例子中,Counter类实现了__iter__和__next__方法,使其成为一个迭代器对象。__iter__方法返回一个生成器函数,而__next__方法定义了生成器函数的执行逻辑。
通过将Counter对象用于for循环中,可以逐步遍历生成器函数中的值,并输出到控制台上。
总结来说,yield关键字的基本用法就是创建一个生成器函数,通过yield语句来返回值。生成器函数可以通过多次调用next()函数来逐步执行,并返回yield关键字后面的值。
同时,yield关键字还可以用于实现迭代器对象,使其可以通过for循环来遍历生成器函数中的值。
3、迭代器协议
迭代器协议是 Python 中用来定义可迭代对象的一种协议。可迭代对象是指支持迭代操作的对象,例如列表、字符串、字典等。迭代器协议的核心是通过两个特殊的方法来实现迭代操作:__iter__
和__next__
。
__iter__
方法返回一个迭代器对象,该迭代器对象必须包含__next__
方法,并在迭代时返回下一个元素。当没有更多元素时,__next__
方法会抛出StopIteration
异常。
下面是一个简单的示例,展示了如何实现一个迭代器协议:
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):
raise StopIteration
value = self.data[self.index]
self.index += 1
return value
# 使用迭代器
my_iter = MyIterator([1, 2, 3])
for item in my_iter:
print(item)
输出结果为:
1
2
3
在上面的示例中,MyIterator
类实现了迭代器协议,通过__iter__
方法返回自身,并通过__next__
方法来返回下一个元素。在使用迭代器时,我们可以通过for
循环来遍历迭代器对象,并通过__next__
方法获取每个元素。
需要注意的是,一旦迭代器对象抛出了StopIteration
异常,它就不能再被迭代了。如果我们想重新迭代,需要重新创建迭代器对象。
除了使用自定义类来实现迭代器协议,Python 还提供了一些内置的可迭代对象,例如list
、str
、dict
等。这些内置对象在迭代时会自动实现迭代器协议,因此我们可以直接在它们上面使用for
循环来进行迭代操作。
二、装饰器
1、函数装饰器
在Python中,函数装饰器是一种特殊的函数,用于修改其他函数的功能。它们可以在不修改原函数定义的情况下,添加一些额外的功能或行为。
函数装饰器的基本语法如下:
def decorator_func(original_func):
def wrapper_func(*args, **kwargs):
# 添加额外的功能或行为
return original_func(*args, **kwargs)
return wrapper_func
通过使用@
符号,我们可以应用一个装饰器到函数上,例如:
@decorator_func
def my_function():
# 函数的定义
pass
装饰器函数decorator_func
接收一个原始函数original_func
作为参数,并返回一个新的内部函数wrapper_func
。内部函数wrapper_func
添加了额外的功能或行为,然后调用原始函数original_func
并返回其结果。
下面是一个简单的示例,使用装饰器在函数调用前后打印日志信息:
def log_decorator(original_func):
def wrapper_func(*args, **kwargs):
print(f'Calling {original_func.__name__} with args: {args}, kwargs: {kwargs}')
result = original_func(*args, **kwargs)
print(f'{original_func.__name__} returned {result}')
return result
return wrapper_func
@log_decorator
def add_numbers(a, b):
return a + b
result = add_numbers(10, 5)
print(result)
输出:
Calling add_numbers with args: (10, 5), kwargs: {}
add_numbers returned 15
15
在这个例子中,log_decorator
是一个装饰器函数,它接收一个原始函数add_numbers
作为参数,并返回一个新的内部函数wrapper_func
。wrapper_func
在调用add_numbers
之前打印日志信息,在调用之后再次打印结果。最后,我们通过@log_decorator
将装饰器应用到add_numbers
函数上。
需要注意的是,装饰器函数可以具有任意数量的参数,可以是可选位置参数、可选关键字参数,甚至是包含默认值的参数。装饰器函数的参数要与被装饰的函数一致,以确保正确传递参数。
除了上述基本的装饰器功能外,还可以使用装饰器来实现缓存、性能计时、权限控制等更复杂的功能。通过编写不同的装饰器函数,可以实现各种不同的行为和功能。
2、类装饰器
Python类装饰器是一种特殊的装饰器,用于装饰类,而不仅仅是函数。它可以在定义类的时候,对类进行一些额外的操作或修改。
类装饰器的使用方式和函数装饰器类似,但是它的实现方式略有不同。一个类装饰器就是一个类,它接收一个类作为参数,并返回一个新的类。
下面是一个类装饰器的基础示例:
class Decorator:
def __init__(self, cls):
self.cls = cls
def __call__(self, *args, **kwargs):
obj = self.cls(*args, **kwargs)
# 对类进行一些额外的操作或修改
return obj
@Decorator
class MyClass:
pass
在上面的例子中,Decorator
是一个类装饰器。它接收一个类作为参数,并在创建类的实例时进行一些额外的操作。通过在类定义之前添加@Decorator
,我们可以将Decorator
应用到MyClass
类上。
下面是一个更具体的实例,展示了类装饰器如何对类进行修改:
class AddAttribute:
def __init__(self, attribute):
self.attribute = attribute
def __call__(self, cls):
setattr(cls, self.attribute, None)
return cls
@AddAttribute('name')
class Person:
pass
# 使用类装饰器添加了一个名为'name'的属性
p = Person()
print(p.name) # 输出: None
在上面的例子中,AddAttribute
是一个类装饰器,它接收一个参数attribute
,并将其作为类的属性添加到被装饰的类上。通过在类定义之前使用@AddAttribute('name')
,我们将'name'
属性添加到Person
类上。
类装饰器可以对类进行修改,添加属性或方法,也可以替换类的实现。使用类装饰器可以在不修改原始类定义的情况下,对类进行一些额外的操作或修改。
3、装饰器应用场景
装饰器是 Python 中一个非常强大和常用的功能,主要用于对函数或类进行额外的操作和功能增加,而无需修改原始函数或类的代码。装饰器可以用于实现日志记录、性能测试、权限控制等功能。
装饰器的基本原理是将一个函数作为参数传递给另外一个函数,然后返回一个新的函数。这个新的函数封装了原始函数,并在执行原始函数之前或之后添加了额外的功能。
下面是一个简单的装饰器实例,用来记录函数的执行时间:
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
duration = end_time - start_time
print(f"Function {func.__name__} executed in {duration} seconds")
return result
return wrapper
@timer
def some_function():
# 假设这里是一些耗时的任务
time.sleep(2)
在上面的代码中,timer
是一个装饰器函数,它接受一个函数作为参数,并返回一个新的函数 wrapper
。在 wrapper
函数内部,计算了原始函数执行的时间,并打印出来。最后,返回原始函数的执行结果。
使用装饰器的语法糖 @timer
可以简化函数装饰的过程。在定义 some_function
函数时,使用 @timer
装饰器对其进行装饰。当调用 some_function
时,实际上会执行被装饰后的 wrapper
函数,从而实现了记录执行时间的功能。
除了函数装饰器,Python 还支持类装饰器和装饰器链。类装饰器与函数装饰器的原理相同,只不过将函数作为参数的过程变成了将类作为参数。装饰器链是指在一个函数或类上同时使用多个装饰器,装饰器会按照从上到下的顺序依次执行。
装饰器是 Python 中非常方便和强大的特性,可以大大提高代码的可复用性和灵活性。在实际开发中,我们可以根据需要自定义装饰器来实现各种功能的增加和扩展。
三、上下文管理器
1、with语句
Python的with
语句用于管理资源的分配和释放,可以在代码块执行结束后自动释放资源,无论代码块内部是否发生异常。with
语句的基本语法结构如下:
with context_expression [as target]:
with_suite
context_expression
是一个返回上下文管理器的表达式。上下文管理器是一个定义了__enter__()
和__exit__()
方法的对象。__enter__()
方法在进入代码块之前被调用,而__exit__()
方法在代码块执行结束后被调用。target
是可选的,用于将上下文管理器的返回值赋给一个变量。
下面是一个简单的示例,展示了如何使用with
语句来操作文件:
with open('file.txt', 'r') as f:
data = f.read()
print(data)
在这个示例中,open('file.txt', 'r')
返回了一个文件对象,该对象是一个上下文管理器。当代码块结束后,文件对象的__exit__()
方法会被自动调用,关闭文件。
除了文件,with
语句还可以用于其他一些对象,比如线程锁、网络连接等需要手动释放的资源。
import threading
lock = threading.Lock()
with lock:
# 代码块
pass
这个示例展示了如何使用with
语句来操作线程锁。一旦代码块执行结束,线程锁会自动释放。
总结来说,with
语句提供了一种简洁的方式来管理资源的分配和释放,可以减少代码的冗余和错误。在需要使用上下文管理器的情况下,建议使用with
语句来代替手动管理资源的分配和释放。
2、自定义上下文管理器
上下文管理器是 Python 中用于管理资源的一种机制。它通过实现 __enter__
和 __exit__
方法来定义一个对象的上下文管理器。
下面是一个简单的示例,展示了如何自定义一个上下文管理器:
class MyContextManager:
def __enter__(self):
print("Entering the context")
# 可以在这里进行一些资源的初始化操作,例如打开文件,建立数据库连接等
# 并返回一个资源对象,使其能够在上下文中使用
def __exit__(self, exc_type, exc_val, exc_tb):
print("Exiting the context")
# 可以在这里进行一些资源的清理操作,例如关闭文件,关闭数据库连接等
# 还可以根据异常信息决定是否抛出异常,如果返回 True,则异常会被忽略
# 使用上下文管理器
with MyContextManager() as resource:
# 在这里可以使用资源对象进行一些操作
在上述示例中,MyContextManager
类定义了两个特殊方法 __enter__
和 __exit__
。在 with
语句的上下文中,__enter__
方法会被调用,返回的资源对象将会被赋值给 as
后的变量(在本例中是 resource
)。在 with
语句块执行完毕后,无论是正常执行还是发生异常,__exit__
方法都会被调用,用于清理资源或处理异常。
实际使用中,可以在 __enter__
方法中执行一些初始化操作,例如打开文件、建立数据库连接等。在 __exit__
方法中,可以进行对应的清理操作,例如关闭文件、关闭数据库连接等。如果发生异常,可以根据需要决定是否抛出异常,如果返回 True,则异常会被忽略。
上下文管理器可以确保资源的正确打开和关闭,避免资源泄漏和错误的发生。
四、协程与异步编程
Python协程是一种用于实现异步编程的技术。它能够让程序在遇到IO操作时,不阻塞主线程,而是将控制权交给其他任务,等到IO操作完成后再切换回来。
Python协程使用asyncio
模块来实现。通过定义async
修饰的函数,可以将其变成一个协程。协程使用await
关键字来暂停当前任务,并且在IO操作完成后继续执行。
使用协程可以实现高效的异步编程。在传统的多线程编程中,每个线程都需要占用一定的系统资源,而协程只需要一个线程,可以同时执行多个任务,并且切换任务的代价非常低。这使得协程可以在处理大量IO密集型任务时,更加高效地利用系统资源。
异步编程可以简化编程模型,提高程序的可读性和可维护性。在传统的同步阻塞IO模型中,需要使用回调函数或者多线程来处理并发IO操作,逻辑复杂,容易出错。而使用协程可以以顺序的方式编写代码,让程序看起来更加直观、易懂。
总的来说,Python协程是一种用于实现异步编程的技术,通过将IO操作交给其他任务处理,能够提高程序的并发性能,简化编程模型。
1、asyncio库
asyncio是Python 3.4版本中引入的一个标准库,用于编写异步代码。它提供了一整套用于编写异步代码的基础设施,包括异步I/O,协程,任务调度等。
下面是asyncio的一些基础概念和用法示例:
a.协程(coroutine):协程是asyncio的核心概念之一,它是一种特殊的函数,可以中断执行,并在后续的某个时刻恢复执行。定义协程函数时要使用async def
关键字。
import asyncio
async def hello():
print("Hello")
await asyncio.sleep(1)
print("World")
asyncio.run(hello())
上述示例中,await asyncio.sleep(1)
会暂停协程的执行1秒钟,然后再继续执行。
b.事件循环(event loop):事件循环是asyncio的驱动引擎,它负责协调和调度协程的执行。可以使用asyncio.get_event_loop()
获取当前线程的事件循环。
import asyncio
async def say_hello():
print("Hello")
await asyncio.sleep(1)
print("World")
loop = asyncio.get_event_loop()
loop.run_until_complete(say_hello())
loop.close()
上述示例中,loop.run_until_complete(say_hello())
会将say_hello()
函数注册到事件循环,并运行直到协程执行完毕。
c.异步I/O(async I/O):asyncio提供了一系列的异步I/O操作,例如文件读写,网络通信等。可以使用asyncio.open()
打开文件,asyncio.create_connection()
建立网络连接等。
import asyncio
async def read_file():
async with asyncio.open("myfile.txt") as f:
content = await f.read()
print(content)
loop = asyncio.get_event_loop()
loop.run_until_complete(read_file())
loop.close()
上述示例中,await asyncio.open("myfile.txt")
会打开文件,并返回一个异步文件对象,然后可以使用await f.read()
读取文件内容。
d.并发执行(concurrency):asyncio可以实现并发执行多个协程,从而提高程序的性能。可以使用asyncio.gather()
同时执行多个协程。
import asyncio
async def say_hello():
print("Hello")
await asyncio.sleep(1)
print("World")
async def say_hi():
print("Hi")
await asyncio.sleep(1)
print("There")
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(say_hello(), say_hi()))
loop.close()
上述示例中,asyncio.gather(say_hello(), say_hi())
会同时执行say_hello()
和say_hi()
两个协程。
这只是asyncio的一部分功能,它还提供了很多其他的功能和用法,如任务调度、定时器、异步锁等。可以参考官方文档来了解更多信息。
2、await关键字
在Python中,await
关键字用于暂停当前协程的执行,等待一个异步操作的结果。它只能在异步函数(用async
修饰的函数)中使用。
await
关键字后面可以跟随一个异步操作,例如一个awaitable
对象,如coroutine
、Future
、Task
等。在等待异步操作完成期间,await
将暂停当前协程的执行,将控制权交给事件循环,其他协程可以继续执行。
当异步操作完成后,await
将会恢复协程的执行,并将异步操作的结果返回。如果异步操作抛出异常,则await
将会引发异常。
下面是一个使用await
的简单示例:
import asyncio
async def fetch_data(url):
# 模拟异步IO操作
await asyncio.sleep(1)
return 'Data fetched from {}'.format(url)
async def main():
task = asyncio.create_task(fetch_data('https://www.example.com'))
result = await task
print(result)
asyncio.run(main())
在上面的示例中,fetch_data
函数模拟了一个异步IO操作,并使用await
暂停协程的执行等待sleep
函数完成。在main
函数中,使用create_task
创建了一个Task
对象,然后使用await
等待该任务完成,并打印结果。
需要注意的是,await
关键字只能在异步函数中使用。如果要在普通函数中使用类似的功能,可以使用asyncio.run_coroutine_threadsafe
函数包装异步操作。
3、异步函数
引言: 在许多编程语言中,同步编程是主流的编写方式,即代码按照顺序依次执行,直到完成所有任务。然而,并不是所有情况下都适合同步编程,有些任务需要在后台并发地执行,以提高程序的性能和效率。Python 提供了一种异步编程模式,可以轻松地创建异步函数和协程,从而实现并发执行任务。
异步编程的优点:
- 提高程序的性能和效率,特别是在处理网络请求、IO 操作和并发任务的情况下。
- 使程序更加响应式,能够同时处理多个任务,提升用户体验。
- 简化复杂的并发编程,提供更加简洁和可读性的代码。
异步函数的基础:
- 异步函数的定义:使用
async def
关键字来定义异步函数,函数体内可以包含await
表达式,用于挂起函数的执行并等待其他异步任务的完成。 - 异步函数的调用:异步函数的调用方式与普通函数相同,但是需要使用
await
关键字来等待异步函数的执行结果。 - 异步上下文管理器:使用
async with
关键字来定义异步上下文管理器,用于在异步代码块中管理资源的分配和释放。
示例一:异步函数的定义和调用
import asyncio
async def greet(name):
print(f"Hello, {name}!")
await asyncio.sleep(1) # 模拟耗时操作
print("Goodbye!")
async def main():
await greet("Alice")
await greet("Bob")
asyncio.run(main())
示例二:异步上下文管理器的使用
import asyncio
class AsyncContextManager:
async def __aenter__(self):
print("Entering...")
await asyncio.sleep(1) # 模拟耗时操作
async def __aexit__(self, exc_type, exc_val, exc_tb):
print("Exiting...")
await asyncio.sleep(1) # 模拟耗时操作
async def main():
async with AsyncContextManager():
print("Inside the context")
asyncio.run(main())
总结: 异步函数是 Python 中异步编程的基础,它能够实现并发执行任务和提高程序性能。通过使用 async def
关键字定义异步函数,以及使用 await
表达式等待其他异步任务的完成,可以方便地创建异步函数和协程。此外,Python 还提供了异步上下文管理器,用于在异步代码块中管理资源的分配和释放。
##欢迎关注交流,开发逆商潜力,提升个人反弹力: