如何系统地学习Python(三)高级特性

一、生成器与迭代器

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 还提供了一些内置的可迭代对象,例如liststrdict等。这些内置对象在迭代时会自动实现迭代器协议,因此我们可以直接在它们上面使用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_funcwrapper_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对象,如coroutineFutureTask等。在等待异步操作完成期间,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 提供了一种异步编程模式,可以轻松地创建异步函数和协程,从而实现并发执行任务。

异步编程的优点:

  1. 提高程序的性能和效率,特别是在处理网络请求、IO 操作和并发任务的情况下。
  2. 使程序更加响应式,能够同时处理多个任务,提升用户体验。
  3. 简化复杂的并发编程,提供更加简洁和可读性的代码。

异步函数的基础:

  1. 异步函数的定义:使用 async def 关键字来定义异步函数,函数体内可以包含 await 表达式,用于挂起函数的执行并等待其他异步任务的完成。
  2. 异步函数的调用:异步函数的调用方式与普通函数相同,但是需要使用 await 关键字来等待异步函数的执行结果。
  3. 异步上下文管理器:使用 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 还提供了异步上下文管理器,用于在异步代码块中管理资源的分配和释放。

##欢迎关注交流,开发逆商潜力,提升个人反弹力:

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

runqu

你的鼓励是我创作的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值