Python面试题(二)

今天我们继续聊聊Python相关的一些面试题目,前面的文章已经提到几个比较基础的问题,比如 Python 的特点、List 和 Tuple 的区别、深拷贝与浅拷贝、GIL 以及字典为什么这么快。

这一篇继续整理三个 Python 面试知识点:装饰器、生成器以及迭代器机制。这三个概念很多人刚学 Python 时都会觉得有点抽象,但其实理解之后,会发现它们是 Python 非常优雅的一套设计。

当然,以下内容仅是博主的个人理解与整理,如果有误,欢迎指正。

一、Python装饰器

Python的装饰器是什么?

简单说,

装饰器本质上就是一个函数 ,用来"包装 "另一个函数,从而在不修改原函数代码的情况下给它增加功能。

比如

python 复制代码
def log(func):
    def wrapper():
        print("start")
        func()
        print("end")
    return wrapper

这里的 log 就是一个装饰器函数。它接收一个函数 func 作为参数,然后在内部定义了一个新的函数 wrapper。在 wrapper 中,我们在函数执行前后分别打印了一些信息。

比如我们有一个函数如下

python 复制代码
def say_hello():
    print("hello")

现在希望在执行这个函数时打印一些日志,如果不用装饰器,可能会这样写:

python 复制代码
def say_hello():
    print("start")
    print("hello")
    print("end")

问题是,如果有很多函数都需要这样的功能,我们就要在每个函数里重复写同样的代码,这显然不太优雅。

装饰器就是为了解决这个问题。我们可以这样使用它:

python 复制代码
@log
def say_hello():
    print("hello")

这样当调用这个函数时,就可以实现前面的打印效果

很多初学者第一次看到 @log 时会觉得有点陌生,其实 Python 在背后做的事情很简单,本质上相当于:

python 复制代码
say_hello = log(say_hello)

也就是说,装饰器只是把原函数传进去,然后返回一个新的函数。

在实际开发中,装饰器的应用非常广泛。例如:

  • Web 框架中的 路由

  • 权限校验

  • 日志记录

  • 性能统计

  • 缓存处理

如果你用过 Flask,就会看到类似这样的代码:

python 复制代码
@app.route("/")
def index():
    return "Hello"

这里的 @app.route 本质上就是一个装饰器。

所以从设计角度来看,装饰器其实是一种非常典型的 AOP(面向切面编程)思想。

二、Python生成器

生成器是什么?

在 Python 中,生成器是一种可以按需生成数据的对象 。它最大的特点就是:不会一次性把所有数据都生成出来,而是需要的时候才生成。

生成器通常和一个关键字一起出现,那就是 yield。

我们先看一个简单的例子。

python 复制代码
def my_generator():
    yield 1
    yield 2
    yield 3

当我们调用这个函数时

python 复制代码
g = my_generator()

此时并不会立刻执行函数,而是返回一个 生成器对象。

当我们逐个取值时:

python 复制代码
print(next(g))
print(next(g))
print(next(g))

"""
1
2
3

"""

每调用一次 next(),函数就会执行到下一个 yield 位置,并返回对应的值。

如果你熟悉普通函数,可以把 yield 理解为一种 "暂停并返回" 的机制。函数运行到 yield 时会暂停,下次再继续从这个位置往下执行。

生成器最大的优势是 节省内存。

举个很典型的例子。如果我们想生成一千万个数字:

python 复制代码
nums = [i for i in range(10000000)]

这会在内存中一次性创建一个非常大的列表。

而如果用生成器:

python 复制代码
nums = (i for i in range(10000000))

此时 Python 不会真正创建这一千万个数字,而是 用一个生成器按需生成。只有当你遍历的时候,数据才会逐个产生。

因此生成器特别适合处理:

  • 大数据集

  • 流式数据

  • 文件读取

  • 网络数据流

例如 Python 中非常经典的写法:

python 复制代码
for line in open("file.txt"):
    print(line)

其实文件对象本身就是一个 迭代器 + 生成器式读取,每次只读取一行,而不是一次把整个文件读入内存。

三、Python 迭代器和可迭代对象

很多人在学习 Python 时会遇到两个很像的概念:

可迭代对象(Iterable)
迭代器(Iterator)

这两个概念其实是 Python 迭代机制的核心。

简单来说,可迭代对象就是"可以被遍历的对象"。

例如我们经常写:

python 复制代码
for i in [1,2,3]:
    print(i)

这里的列表 [1,2,3] 就是一个可迭代对象。

Python 中很多数据结构都是可迭代的,比如:

  • list

  • tuple

  • dict

  • string

  • set

只要一个对象可以被 for 循环遍历,我们通常就可以认为它是可迭代对象。

从实现角度来说,一个对象只要实现了 __iter__() 方法,就可以被称为可迭代对象。

不过 for 循环真正工作的对象,其实并不是可迭代对象本身,而是 迭代器。

迭代器是一种更底层的对象,它需要实现两个方法:

__next__() 的作用就是返回下一个元素,如果数据已经遍历完,就会抛出 StopIteration 异常。

举个简单例子,我们可以手动创建一个迭代器:

python 复制代码
nums = [1,2,3]

it = iter(nums)

print(next(it))
print(next(it))
print(next(it))

输出:1 2 3

这里的流程其实是:

  1. iter(nums) 把列表变成一个迭代器

  2. next(it) 每次获取下一个元素

而 for 循环其实就是帮我们自动完成了这些步骤。Python 在内部大致做的是这样的事情:

python 复制代码
it = iter(nums)

while True:
    try:
        item = next(it)
        print(item)
    except StopIteration:
        break

所以总结一句话:

可迭代对象是"可以被遍历的对象",而迭代器是"真正执行遍历动作的对象"。

另外,前面提到的 生成器其实也是一种特殊的迭代器 。只要函数中包含 yield,Python 就会自动帮我们创建一个迭代器对象。


总结

本文我们主要整理了 Python 面试中另外三个非常经典的问题。

装饰器 其实就是一个函数包装器,它可以在不修改 原函数代码的情况下扩展功能,在 Web 框架、日志记录和权限控制中都有大量应用。

生成器 则是一种非常优雅的数据生成方式,通过 yield 按需产生数据 ,可以大幅节省内存,非常适合处理大规模数据或流式数据。

而迭代器和可迭代对象 则构成了 Python 的整个迭代机制。像 for 循环、生成器、文件读取等功能,本质上都建立在这套机制之上。

理解了这些概念之后,你会发现 Python 在很多设计上其实都非常统一。

相关推荐
狗凯之家源码网7 小时前
全新 PHP 轻量客服聊天室源码深度评测
开发语言·php·聊天室系统
凤山老林7 小时前
Spring Boot 启动冲刺:耗时剖析、懒加载策略与事件驱动初始化优化
spring boot·后端·python
小白快快跑哦7 小时前
python-字符串全解(六):正则表达式-逻辑运算或
python·正则表达式·字符串·逻辑运算
远离UE47 小时前
UE5 Substrate Thin Film 源码拆析
开发语言·javascript·ue5
keyipatience7 小时前
JavaScript学习(1)书写位置,变量、数据类型、运算符
开发语言·前端·javascript·css·学习
Thinker QAQ8 小时前
并发编程(九):BlockingQueue 与 Channel——语言层的原子性、可见性与有序性
java·python·go·并发编程·channel·blockingqueue·message passing
道满科技8 小时前
Function Calling 参数总出错?只修参数就行
linux·windows·python
栈帧之外8 小时前
【C++】STL之set
开发语言·c++
霸道流氓气质9 小时前
RAG 可观测性与生产监控实战:四层遥测模型、五大仪表盘与 OpenTelemetry 全链路追踪的 Java 生产级实现
java·人工智能·python
catchadmin9 小时前
免费可商用 PHP 管理后台 CatchAdmin V5.4.1 发布,新增 MCP 支持
开发语言·php