第十一章:Python进阶话题

liftword22小时前技术文章3

11.1 迭代器与生成器

11.1.1 迭代器

理论知识:迭代器是一个实现了迭代器协议的对象,即包含 __iter__() 和 __next__() 方法。__iter__() 方法返回迭代器对象本身,__next__() 方法返回容器的下一个元素,如果没有元素则引发 StopIteration 异常。Python 中的许多数据结构(如列表、元组、字典等)都是可迭代对象,可通过 iter() 函数将其转换为迭代器。迭代器允许我们逐个访问集合中的元素,而无需一次性加载整个集合到内存中,这在处理大数据集时非常高效。

示例代码

my_list = [1, 2, 3, 4, 5]
my_iterator = iter(my_list)

try:
    while True:
        element = next(my_iterator)
        print(element)
except StopIteration:
    pass

代码解释

  • 首先创建一个列表 my_list,然后使用 iter() 函数将其转换为迭代器 my_iterator。
  • 在 while 循环中,通过 next() 函数不断获取迭代器的下一个元素并打印。当没有更多元素时,next() 函数会引发 StopIteration 异常,此时通过 try - except 语句捕获并结束循环。

11.1.2 生成器

理论知识:生成器是一种特殊的迭代器,它的创建方式更加简洁。生成器使用 yield 关键字来暂停函数的执行并返回一个值,当再次调用生成器时,它会从暂停的地方继续执行。生成器函数在调用时不会立即执行函数体,而是返回一个生成器对象。生成器同样具有惰性求值的特点,只有在需要时才生成值,从而节省内存。

示例代码

def number_generator(n):
    for i in range(n):
        yield i


gen = number_generator(5)
for num in gen:
    print(num)

代码解释

  • 定义了一个生成器函数 number_generator,它接受一个参数 n,在函数内部使用 yield 关键字依次返回 range(n) 中的值。
  • 调用 number_generator(5) 创建一个生成器对象 gen,然后通过 for 循环迭代这个生成器对象,每次迭代时,生成器函数从上次暂停的地方继续执行,生成下一个值并赋值给 num 进行打印。

11.2 装饰器

11.2.1 理论知识

装饰器是 Python 中一种强大的语法结构,本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。装饰器可以在不修改原函数代码的情况下,为原函数添加额外的功能,如日志记录、性能测试、权限验证等。装饰器使用 @ 符号加上装饰器函数名,放在需要装饰的函数定义之前。

11.2.2 示例代码

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数 {func.__name__}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} 函数调用结束")
        return result
    return wrapper


@log_decorator
def add_numbers(a, b):
    return a + b


result = add_numbers(3, 5)
print(f"两数之和: {result}")

代码解释

  • 定义了一个装饰器函数 log_decorator,它接受一个函数 func 作为参数。在 log_decorator 内部定义了一个 wrapper 函数,wrapper 函数在调用原函数 func 前后分别打印日志信息,然后返回原函数的执行结果。log_decorator 最后返回 wrapper 函数。
  • 使用 @log_decorator 装饰 add_numbers 函数,这相当于执行了 add_numbers = log_decorator(add_numbers)。
  • 调用 add_numbers(3, 5) 时,实际调用的是被装饰后的 wrapper 函数,因此会先打印调用函数的日志,执行加法运算后再打印函数调用结束的日志,最后返回并打印两数之和。

11.3 上下文管理器

11.3.1 理论知识

上下文管理器用于管理资源的分配和释放,确保在代码块开始时资源被正确分配,在代码块结束时资源被正确释放。例如,文件的打开和关闭、数据库连接的建立和断开等场景。Python 中的 with 语句就是基于上下文管理器实现的。要创建自定义的上下文管理器,可以定义一个包含 __enter__() 和 __exit__() 方法的类,或者使用 contextlib.contextmanager 装饰器来创建基于生成器的上下文管理器。

11.3.2 示例代码(基于类的上下文管理器)

class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file

    def __exit__(self, exc_type, exc_value, traceback):
        if self.file:
            self.file.close()


with FileManager('example.txt', 'w') as file:
    file.write('这是使用自定义上下文管理器写入的内容')

代码解释

  • 定义了 FileManager 类作为上下文管理器。__init__() 方法初始化文件名和打开模式,并将文件对象初始化为 None。
  • __enter__() 方法打开文件并返回文件对象,这个返回值会赋值给 with 语句中的 file 变量。
  • __exit__() 方法在 with 代码块结束时被调用,负责关闭文件。无论 with 代码块中是否发生异常,__exit__() 都会执行。

11.3.3 示例代码(基于生成器的上下文管理器)

from contextlib import contextmanager


@contextmanager
def file_manager(filename, mode):
    file = open(filename, mode)
    try:
        yield file
    finally:
        file.close()


with file_manager('example.txt', 'r') as file:
    content = file.read()
    print(content)

代码解释

  • 使用 contextlib.contextmanager 装饰器定义了 file_manager 函数作为上下文管理器。函数内部打开文件,然后使用 yield 暂停函数执行并返回文件对象,这个文件对象会赋值给 with 语句中的 file 变量。
  • yield 之后的代码在 with 代码块结束时执行,这里使用 finally 确保无论是否发生异常,文件都会被关闭。

11.4 元类

11.4.1 理论知识

元类是创建类的类,它定义了类的结构和行为。在 Python 中,所有的类都是 type 元类的实例。通过自定义元类,可以控制类的创建过程,例如动态修改类的属性、方法,或者对类进行验证等。元类的使用场景相对较少,但在一些高级的框架开发中非常有用。

11.4.2 示例代码

class MyMeta(type):
    def __new__(cls, name, bases, attrs):
        attrs['new_attribute'] = '这是通过元类添加的属性'
        return super().__new__(cls, name, bases, attrs)


class MyClass(metaclass = MyMeta):
    pass


obj = MyClass()
print(obj.new_attribute)

代码解释

  • 定义了一个元类 MyMeta,它继承自 type。__new__() 方法是元类中用于创建类对象的方法,它接受类名 name、基类元组 bases 和属性字典 attrs 作为参数。
  • 在 __new__() 方法中,向 attrs 字典添加了一个新的属性 new_attribute,然后通过调用父类的 __new__() 方法创建并返回新的类对象。
  • 定义 MyClass 类时,指定 metaclass = MyMeta,这使得 MyClass 由 MyMeta 元类创建。
  • 创建 MyClass 的实例 obj,并访问通过元类添加的 new_attribute 属性并打印。

相关文章

Python | 一文搞懂self

关于self在Python中,self是一个关键字,它表示类实例本身。通常,self是在类方法中的第一个参数传递的。通过使用self,我们可以访问类的属性和方法。当一个类定义后,我们可以使用它来创建对...

python self是什么鬼,其本质就是特殊的形参

小伙伴们能真正理解 self 是什么东西吗?现在我从实质上为小伙伴们讲解一下 self。self 的实质是形参,现通过普通形参,来讲解特殊形参 self看基本概念的理解普通形参:通过 函数(参数) 方...

为什么python的self参数必须显式声明?隐式this才是万恶之源

杂谈python中存在 self 这个参数,记得有个朋友是写 java 的,当他看到python中的代码立刻明白了它的用途。他问我:“为什么python中的 self不能像this一样,隐式声明多好,...

Python这个代码里面x=self是什么意思啊

大家好,我是Python进阶者。一、前言前几天在Python白银交流群【无敌劈叉小狗】问了一个Python基础的问题,问题如下:这个代码里面x=self是什么意思啊?self到底是个什么存在呢?感觉把...

Python super()函数:调用父类的构造方法

前面不止一次讲过,Python 中子类会继承父类所有的类属性和类方法。严格来说,类的构造方法其实就是实例方法,因此毫无疑问,父类的构造方法,子类同样会继承。但我们知道,Python 是一门支持多继承的...

一文带你解读JavaScript的引用类型和函数对象

前言相信做网站对JavaScript再熟悉不过了,它是一门脚本语言,不同于Python的是,它是一门浏览器脚本语言,而Python则是服务器脚本语言,我们不光要会Python,还要会JavaScrip...