Python 面试题

8 阅读21分钟

Python 面试题

使用建议:

  1. 先只看问题,尝试自己口述回答。
  2. 再看标准答法,补齐关键词。
  3. 最后结合你自己的项目经验补一个例子,这样回答会更像真实面试而不是背书。

一、基础认知与语言特性

解释型语言 Python 和编译型语言有什么区别?

Python 通常被称为解释型语言,代码先编译成字节码,再由解释器逐步执行; 编译型语言通常会先整体编译成机器码后再运行。 解释型语言开发效率高、跨平台好,但运行时通常比纯编译型语言慢; 编译型语言通常执行效率更高,但编译和调试成本可能更大。

Python3 中 is 和 == 有什么区别?

== 比较的是两个对象的值是否相等。 is 比较的是两个对象是不是同一个对象,也就是内存地址是否相同。 比如判断 None 时推荐使用 is None,而不是 == None

Python 中 read、readline、readlines 有哪些区别?

  • read()
    • 一次读取整个文件,或者读取指定字节数。
  • readline()
    • 一次读取一行。
  • readlines()
    • 一次读取所有行,返回列表。

大文件场景不建议直接用 read()readlines(),更推荐逐行遍历文件对象。

什么是 Python 面向对象中的继承特点?

继承就是子类复用父类的属性和方法,并可以扩展或重写父类行为。 它的核心特点是代码复用、层次化建模和多态支持。 Python 支持单继承,也支持多重继承。

Python 中 any() 和 all() 方法有什么作用?

  • any(iterable)
    • 可迭代对象中只要有一个元素为真,就返回 True
  • all(iterable)
    • 可迭代对象中所有元素都为真,才返回 True

常用于条件批量判断。

nums = [1, 0, 3]
any(nums)   # True
all(nums)   # False

说明 Python3 中装饰器的用法

装饰器本质上是一个函数,用来在不修改原函数代码的前提下,为函数增加额外功能。 常见用途有日志、权限校验、性能统计、缓存等。

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print("before")
        result = func(*args, **kwargs)
        print("after")
        return result
    return wrapper

@log_decorator
def hello():
    print("hello")

说明 Python3 中 yield 的用法

yield 用于定义生成器函数。 函数执行到 yield 时会暂停并返回当前值,下次继续从暂停位置往下执行。 它适合处理大数据、惰性计算和流式读取,优点是节省内存。

说明 Python 中 enumerate() 的用法

enumerate() 可以在遍历序列时同时拿到索引和值。

for index, value in enumerate(["a", "b", "c"], start=1):
    print(index, value)

它比手动维护下标更简洁。

解释 Python 中 //、% 和 ** 运算符

  • //
    • 整除,返回向下取整后的商。
  • %
    • 取模,返回余数。
  • **
    • 幂运算。
7 // 2  # 3
7 % 2   # 1
2 ** 3  # 8

Python 有哪些特点和优点?

常见特点和优点:

  • 语法简洁,学习成本低
  • 开发效率高
  • 标准库和第三方生态丰富
  • 跨平台
  • 支持面向对象、函数式、脚本式等多种编程风格
  • 适合 Web、自动化、数据分析、AI 等多个领域

Python 中深拷贝和浅拷贝有什么区别?

浅拷贝只拷贝最外层对象,内部嵌套对象仍然共享引用。 深拷贝会递归复制所有层级对象,新旧对象互不影响。 常用 copy.copy() 做浅拷贝,copy.deepcopy() 做深拷贝。

Python 中的列表和元组有什么区别?

  • 列表 list 可变,元组 tuple 不可变。
  • 列表适合频繁增删改,元组适合表示不希望被修改的数据。
  • 元组通常比列表更轻量,能作为字典键的前提之一是其内部元素也必须可哈希。

什么是 Python 中的三元表达式?

Python 的三元表达式用于简化简单条件判断。

result = "成年" if age >= 18 else "未成年"

格式是:值1 if 条件 else 值2

请简单介绍 Python 的 Flask 框架,有什么作用?

Flask 是一个轻量级 Python Web 框架,核心简单、扩展灵活。 它常用于开发 Web 网站、RESTful API、后台管理系统和小型服务。 相比 Django,Flask 更轻、更自由,但很多功能需要自己选扩展来组合。

如何在 Python 中管理内存?

Python 主要通过引用计数管理对象生命周期,并辅以垃圾回收机制处理循环引用。 开发中通常不需要手动释放内存,但要注意:

  • 及时关闭文件和网络连接
  • 避免不必要的大对象长期持有
  • 合理使用生成器
  • 避免循环引用和缓存失控

Python 中 help() 函数和 dir() 函数有什么作用?

  • help()
    • 查看对象、函数、类、模块的帮助文档。
  • dir()
    • 查看对象可用的属性和方法列表。

它们都很适合调试和学习新模块时使用。

Python 程序退出时,是否释放所有内存分配?

通常来说,进程退出后,操作系统会回收该进程占用的内存资源。 但如果程序退出前有未刷盘的数据、未关闭的文件或外部资源句柄,可能会带来业务层面的资源问题,所以仍建议显式释放关键资源。

什么是 Python 的字典,有哪些用法?

字典 dict 是键值对映射结构,特点是查找快、读取方便。 常见用法包括:

  • 存储结构化数据
  • 做配置映射
  • 计数统计
  • 实现简单的分支分发
user = {"name": "Tom", "age": 20}
print(user["name"])

什么是 Python 的负索引?

负索引表示从序列末尾开始取值。 -1 表示最后一个元素,-2 表示倒数第二个元素。

s = "python"
s[-1]  # 'n'

Python 中 join() 和 split() 函数有什么区别?

  • join()
    • 把字符串序列按指定分隔符拼接成一个字符串。
  • split()
    • 把一个字符串按指定分隔符拆分成列表。
"-".join(["a", "b"])   # 'a-b'
"a-b".split("-")       # ['a', 'b']

Python 是否区分大小写?

区分。 比如 nameName 是两个不同的标识符。

说明 Python 中标识符的命名规则

命名规则主要有:

  • 只能由字母、数字、下划线组成
  • 不能以数字开头
  • 不能使用关键字
  • 区分大小写

规范上通常建议:

  • 变量和函数使用小写加下划线
  • 类名使用大驼峰
  • 常量使用全大写加下划线

Python 中如何删除字符串中的前置空格?

使用 lstrip()

s = "   hello"
print(s.lstrip())  # 'hello'

Python 中如何将字符串转换为小写?

使用 lower()

"Hello".lower()  # 'hello'

Python 的 pass 语句有什么作用?

pass 表示空操作,占位用。 当语法上必须写语句,但暂时不想实现逻辑时可以使用,比如空函数、空类、空分支。

什么是 Python 的闭包?

闭包指内部函数引用了外部函数作用域中的变量,并且外部函数执行结束后这些变量仍然被保留。 它常用于封装状态、实现装饰器、工厂函数等。

什么是 Python 的关系运算符?

关系运算符用于比较两个值之间的大小或相等关系,包括:

  • ==
  • !=
  • >
  • <
  • >=
  • <=

结果是布尔值。

什么是 Python 的赋值和算术运算符?

赋值运算符常见有:

  • =
  • +=
  • -=
  • *=
  • /=
  • //=
  • %=
  • **=

算术运算符常见有:

  • +
  • -
  • *
  • /
  • //
  • %
  • **

什么是 Python 的逻辑运算符?

逻辑运算符包括:

  • and
  • or
  • not

用于组合多个条件表达式。

什么是 Python 的成员运算符?

成员运算符用于判断某个元素是否在序列、集合、字典等对象中:

  • in
  • not in
"a" in "cat"      # True
1 in [1, 2, 3]    # True

什么是 Python 的身份运算符?

身份运算符用于判断两个变量是否引用同一个对象:

  • is
  • is not

它比较的是对象身份,不是值。

什么是 Python 的位运算符?

位运算符是直接对二进制位进行操作的运算符,包括:

  • & 按位与
  • | 按位或
  • ^ 按位异或
  • ~ 按位取反
  • << 左移
  • >> 右移

常用于底层控制、权限标记、性能敏感场景。

如何在 Python 中使用多进制数字?

Python 支持多种进制字面量:

  • 二进制:
    • 0b1010
  • 八进制:
    • 0o12
  • 十六进制:
    • 0xA

也可以用 bin()oct()hex() 做转换。

Python 中如何获取字典的所有键?

使用 dict.keys()

d = {"a": 1, "b": 2}
print(d.keys())

如果要转成列表,可以使用 list(d.keys())

为什么 Python 不建议使用下划线开头的标识符?

因为下划线开头通常有约定含义:

  • _name
    • 表示内部使用,不建议外部直接访问
  • __name
    • 会触发名称重整,常用于类内部避免命名冲突
  • __name__
    • 通常是系统定义的特殊方法或特殊变量

所以普通业务变量不建议随意以下划线开头,避免语义混乱。

Python 如何声明多个变量并赋值?

可以链式赋值,也可以同时解包赋值。

a = b = c = 10
x, y, z = 1, 2, 3

什么是 Python 元组的解封装?

元组解封装也叫拆包,就是把元组中的多个值一次性赋给多个变量。

t = (1, 2, 3)
a, b, c = t

什么是 Python?为什么它会这么流行?

Python 是一种高级、通用、解释型编程语言。 它流行的原因主要是语法简单、开发效率高、生态强、应用范围广,既适合入门,也适合工程落地。

请列举一些 Python 的应用场景

常见场景包括:

  • Web 开发
  • 自动化运维与测试
  • 数据分析与可视化
  • 人工智能与机器学习
  • 爬虫开发
  • 脚本工具开发
  • 教育教学

Python 有哪些局限性?

常见局限性:

  • 运行速度通常不如 C/C++
  • GIL 对 CPU 密集型多线程有影响
  • 移动端和前端原生场景不占优势
  • 某些强约束超大型项目中,动态类型维护成本会变高

请解释 Python 代码的执行过程?

简化流程可以这样理解:

  1. 编写 .py 源代码。
  2. Python 解释器先把源码编译成字节码。
  3. 字节码交给 Python 虚拟机执行。

如果模块被导入,通常还会生成对应的 .pyc 字节码缓存文件。

Python 有哪些内置数据结构?

常见内置数据结构有:

  • int
  • float
  • bool
  • str
  • list
  • tuple
  • set
  • dict

此外还有 bytesbytearrayrange 等。

Python 中单引号和双引号有什么区别?

本质上没有区别,都是表示字符串。 通常根据字符串内容来选,哪个更方便少转义就用哪个。 如果字符串里本身有单引号,就可以用双引号包裹,反之亦然。


二、常用容器与流程控制

Python 中 append、insert 和 extend 有什么区别?

  • append(x)
    • 在列表末尾追加一个元素。
  • insert(i, x)
    • 在指定位置插入一个元素。
  • extend(iterable)
    • 把另一个可迭代对象中的多个元素依次追加到列表末尾。
lst = [1, 2]
lst.append(3)       # [1, 2, 3]
lst.insert(1, 99)   # [1, 99, 2, 3]
lst.extend([4, 5])  # [1, 99, 2, 3, 4, 5]

Python 中 break、continue、pass 有什么作用?

  • break
    • 立即结束当前循环。
  • continue
    • 跳过本次循环后续代码,进入下一次循环。
  • pass
    • 什么都不做,只是占位。

Python 中 remove、del 和 pop 有什么区别?

  • remove(x)
    • 按值删除列表中第一个匹配项。
  • del
    • 可删除指定索引元素,也可删除整个变量。
  • pop([i])
    • 按索引删除并返回该元素,默认删除最后一个。

Python 中如何实现 switch 语句?

Python 早期没有传统 switch,常见替代方式有:

  • if...elif...else
  • 字典映射
  • Python 3.10+ 的 match...case
def run(cmd):
    actions = {
        "start": lambda: "启动",
        "stop": lambda: "停止"
    }
    return actions.get(cmd, lambda: "未知命令")()

Python 的 range 函数如何运用?请举例说明

range() 用于生成整数序列,常用于循环。

range(5)        # 0,1,2,3,4
range(1, 5)     # 1,2,3,4
range(1, 10, 2) # 1,3,5,7,9
for i in range(3):
    print(i)

如何更改 Python 列表的数据类型?

如果题目想表达“把列表元素转换成其他类型”,常见做法是用列表推导式或 map()

lst = ["1", "2", "3"]
nums = [int(x) for x in lst]

如果是把列表整体转换为其他容器,可以使用 tuple(lst)set(lst) 等。

Python 中怎么注释代码?

  • 单行注释:
    • 使用 #
  • 多行说明:
    • 常用连续多行 #
  • 文档字符串:
    • 使用三引号,常用于模块、类、函数说明

Python 中的 != 和 is not 运算符有什么区别?

  • !=
    • 判断值是否不相等。
  • is not
    • 判断是不是不同一个对象。

一个比较值,一个比较身份。

Python 是否有 main 函数?

Python 没有像 C/Java 那样固定语法要求的 main 函数。 但工程里通常会写:

if __name__ == "__main__":
    main()

这是一种约定,用于区分“脚本直接运行”和“模块被导入”。

Python 的 iterables 和 iterators 有什么区别?

  • iterable
    • 可迭代对象,可以被 for 遍历,比如列表、元组、字符串。
  • iterator
    • 迭代器,是带有状态、可逐个返回元素的对象,支持 next()

可迭代对象通过 iter() 可以得到迭代器。

Python 中的 Map 函数有什么作用?怎么使用?

map() 会把一个函数依次作用到可迭代对象的每个元素上,返回一个迭代器。

nums = [1, 2, 3]
result = map(lambda x: x * 2, nums)
print(list(result))  # [2, 4, 6]

Python 中的 Filter 函数有什么作用?怎么使用?

filter() 用于筛选元素,把函数返回值为真的元素保留下来。

nums = [1, 2, 3, 4]
result = filter(lambda x: x % 2 == 0, nums)
print(list(result))  # [2, 4]

Python 中 reduce 函数有什么作用?怎么使用?

reduce() 会把一个函数累计作用到序列上,实现归并计算。 它位于 functools 模块中。

from functools import reduce

nums = [1, 2, 3, 4]
result = reduce(lambda x, y: x + y, nums)
print(result)  # 10

什么是 Python 的 pickling 和 unpickling?

  • pickling
    • 把 Python 对象序列化成字节流,便于保存或传输。
  • unpickling
    • 把字节流反序列化还原成 Python 对象。

通常使用 pickle 模块。 要注意:不要反序列化不可信来源的数据,因为有安全风险。

什么是 Python 的生成器?

生成器是按需产生数据的对象,不会一次性把所有结果放入内存。 可以通过包含 yield 的函数创建,也可以用生成器表达式创建。 适合大数据处理和流式计算。

Python 中如何使用索引反转字符串?

可以使用切片:

s = "python"
print(s[::-1])  # 'nohtyp'

什么是 Python 的 Lambda 函数,有哪些应用场景?

lambda 是匿名函数,适合写简单、一次性的函数。 常见应用场景有:

  • map()filter()sorted()key
  • 简单回调
  • 临时计算逻辑
square = lambda x: x * x

Python 的迭代器和生成器有什么区别?

生成器本质上是一种特殊的迭代器。 区别在于:

  • 迭代器是更泛化的概念,只要实现迭代协议即可
  • 生成器通常由 yield 自动生成,写法更简洁

所以可以说:所有生成器都是迭代器,但不是所有迭代器都是生成器。

Python 正则表达式中 match 和 search 有什么区别?

  • match()
    • 只从字符串开头开始匹配。
  • search()
    • 扫描整个字符串,找到第一个匹配位置即可。

所以 search() 的适用范围更广。

为什么 Python 中没有函数重载?

因为 Python 函数名本质上是对象引用,同名函数后定义的会覆盖前定义的。 Python 更鼓励通过默认参数、可变参数、关键字参数、类型判断等方式实现“类似重载”的效果。


三、对象模型、函数与作用域

Python 的 initnew 方法有什么区别?

  • __new__
    • 负责创建实例,返回对象本身。
  • __init__
    • 负责初始化实例,在对象创建后执行。

__new__ 常见于不可变对象子类化、单例模式等场景,普通业务里更常用的是 __init__

你知道哪些 Python 魔术方法?

常见魔术方法包括:

  • __init__
    • 初始化
  • __new__
    • 创建实例
  • __str__ / __repr__
    • 字符串表示
  • __len__
    • 长度
  • __iter__ / __next__
    • 迭代
  • __getitem__ / __setitem__
    • 下标访问
  • __enter__ / __exit__
    • 上下文管理
  • __call__
    • 对象可调用

Python 函数参数 *arg 和 **kwargs 有什么区别?怎么使用?

  • *args
    • 接收位置参数,多余参数会打包成元组。
  • **kwargs
    • 接收关键字参数,多余参数会打包成字典。
def func(*args, **kwargs):
    print(args)
    print(kwargs)

请介绍 Python 中变量的作用域?

Python 常见作用域可以记成 LEGB

  • Local
    • 局部作用域
  • Enclosing
    • 外层嵌套函数作用域
  • Global
    • 全局作用域
  • Built-in
    • 内置作用域

变量查找顺序通常按这个顺序进行。

Python 2 和 Python 3 有什么区别?

常见区别包括:

  • print
    • Python 2 是语句,Python 3 是函数
  • 字符串默认编码处理不同,Python 3 区分更清晰
  • range
    • Python 3 返回惰性对象
  • xrange 在 Python 3 中被移除
  • 除法行为有变化,Python 3 中 / 更符合真实除法
  • Python 3 对 Unicode 支持更好

面试里一般补一句:现在新项目基本都使用 Python 3。

什么是 “猴子补丁”(monkey patching)?

猴子补丁是指在运行时动态修改模块、类或对象的属性或方法。 它很灵活,常用于测试、临时修复、mock,但滥用会让代码可维护性变差。

如何在 Python 中实现字符串替换操作?

最常用的是 replace()

s = "hello world"
print(s.replace("world", "python"))

复杂替换可以使用正则表达式的 re.sub()

Python 在什么情况下会出现 KeyError、TypeError、ValueError?

  • KeyError
    • 访问字典中不存在的键。
  • TypeError
    • 操作或函数作用在了不合适的类型上。
  • ValueError
    • 类型没错,但值本身不合法。
int("abc")  # ValueError

什么是 Python 中的模块和包?

  • 模块:
    • 一个 .py 文件就是一个模块。
  • 包:
    • 一个包含多个模块的目录,用于组织代码。

简单理解:模块是代码文件级别的复用,包是目录级别的组织。

你知道哪些 Python 的编码规范?

最常见的是遵循 PEP 8。 例如:

  • 命名风格统一
  • 缩进用 4 个空格
  • 每行长度适中
  • 导入顺序规范
  • 类、函数、模块之间留空行
  • 写有意义的注释和文档字符串

Python 的类和对象有什么区别?

  • 类是抽象模板,定义属性和方法。
  • 对象是类的具体实例,是运行时真正创建出来的实体。

可以理解成“类是图纸,对象是按图纸造出来的东西”。

什么是 Python 类中的 self?

self 表示当前实例对象本身。 实例方法的第一个参数默认写成 self,通过它访问实例属性和其他实例方法。

init 方法在 Python 中有什么作用?

__init__ 是实例初始化方法,在创建对象后自动调用。 它通常用于给实例属性赋初值、建立对象初始状态。

什么是 Python 的 OOPS(面向对象编程)?

OOPS 就是面向对象编程思想,通过类和对象组织程序。 其核心特性通常包括:

  • 抽象
  • 封装
  • 继承
  • 多态

什么是 Python 面向对象的抽象特性?

抽象就是提取事物的核心特征,隐藏不必要的实现细节。 在 Python 中可以通过类、接口风格设计、抽象基类等方式体现抽象。

什么是 Python 面向对象的封装特性?

封装就是把数据和操作数据的方法绑定在一起,并对外隐藏实现细节。 这样可以降低耦合、提高安全性和可维护性。

什么是 Python 面向对象的多态特性?

多态是指同一个接口,不同对象可以有不同实现。 在 Python 中,多态更多依赖鸭子类型,不强调必须继承同一个父类。

Python 是否支持多重继承?

支持。 一个类可以继承多个父类。 但多重继承会带来方法查找顺序和设计复杂度问题,所以实际使用要谨慎。

什么是鸭子类型(duck typing)?

鸭子类型强调“关心对象能做什么,而不是它是什么类型”。 只要对象实现了需要的方法或行为,就可以被当作该类型使用。 这是 Python 动态语言风格的重要体现。

为什么 Python 执行速度慢,如何改进?

慢的原因主要有:

  • 动态类型带来额外开销
  • 解释执行开销更高
  • GIL 对某些并发场景有限制

优化方式包括:

  • 使用更高效的数据结构和算法
  • 减少 Python 层循环
  • 使用生成器节省内存
  • 借助 numpypandascython
  • CPU 密集型任务改用多进程或 C 扩展

如何分析 Python 代码的执行性能?

常见方法有:

  • timetimeit 做简单耗时测试
  • cProfile 做性能分析
  • line_profiler 看热点代码
  • 观察内存可用 memory_profiler
  • 针对 SQL、网络、I/O 进一步分层分析

四、文件、标准库与常见工具

Python 中如何读取大文件,例如内存只有 4G,如何读取一个大小为 8G 的文件

核心思路是分块或逐行读取,不要一次性加载到内存。

常见做法:

  • 直接遍历文件对象逐行读取
  • 使用 read(size) 分块读取
  • 使用生成器封装处理逻辑
with open("big.log", "r", encoding="utf-8") as f:
    for line in f:
        process(line)

你使用过哪些 Python 标准库模块?

常见可以回答:

  • ossys
  • jsonre
  • datetime
  • collections
  • functools
  • itertools
  • logging
  • threadingmultiprocessing
  • unittest

面试里最好补你在项目里真实用过的几个模块和场景。

Python 的 re 模块中 split()、sub()、subn() 方法有什么作用?

  • re.split()
    • 按正则规则切分字符串
  • re.sub()
    • 按正则替换字符串
  • re.subn()
    • sub() 类似,但会额外返回替换次数
import re
re.split(r"\s+", "a b   c")
re.sub(r"\d+", "*", "a123b")

Python 的 namedtuple 有什么作用?怎么使用?

namedtuple 是带字段名的元组,可读性比普通元组更好,同时仍保留元组轻量、不可变的特点。

from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
p = Point(1, 2)
print(p.x, p.y)

说明 Python 中的 zip 函数

zip() 用于把多个可迭代对象按位置打包成元组迭代器。

names = ["Tom", "Jerry"]
ages = [20, 18]
print(list(zip(names, ages)))

常用于并行遍历,也常用于矩阵转置。

如何使用 Python 的 random 模块生成随机数、实现随机乱序和随机抽样?

常见方法:

  • random.random()
    • 生成 0~1 之间随机浮点数
  • random.randint(a, b)
    • 生成指定区间随机整数
  • random.shuffle(lst)
    • 原地打乱列表
  • random.choice(seq)
    • 随机取一个元素
  • random.sample(seq, k)
    • 随机抽样多个不重复元素

五、并发编程与性能

Python 中如何实现多线程?

可以使用 threading 模块创建线程,也可以用 concurrent.futures.ThreadPoolExecutor 使用线程池。 多线程更适合 I/O 密集型任务,比如网络请求、文件读写。

请介绍 Python 中多线程和多进程的应用场景,以及优缺点?

多线程:

  • 适合 I/O 密集型任务
  • 线程创建和切换成本相对较低
  • 共享内存方便
  • 但受 GIL 影响,CPU 密集型任务提升有限

多进程:

  • 适合 CPU 密集型任务
  • 可以利用多核
  • 进程隔离更安全
  • 但创建成本更高,通信更复杂

请解释 Python 线程池的工作原理?

线程池本质上是预先创建或统一管理一组线程,把任务放进任务队列后,由空闲线程不断取任务执行。 好处是避免频繁创建和销毁线程,提高资源利用率,也便于控制并发数量。 Python 中常用 ThreadPoolExecutor 来实现线程池。

from concurrent.futures import ThreadPoolExecutor

def task(x):
    return x * x

with ThreadPoolExecutor(max_workers=4) as pool:
    results = list(pool.map(task, [1, 2, 3, 4]))

复习建议

如果你是为了面试准备,建议把这些题再按下面几类二次记忆:

  • 基础语法:
    • is/==、运算符、字符串、列表、字典
  • 函数与高级特性:
    • 装饰器、闭包、生成器、lambda、*args/**kwargs
  • 面向对象:
    • 继承、封装、多态、鸭子类型、魔术方法
  • 文件与标准库:
    • read 系列、rerandomcollections
  • 并发与性能:
    • 多线程、多进程、线程池、性能分析

面试回答时尽量遵循这个模板:

  1. 先下定义。
  2. 再说核心区别或特点。
  3. 最后补一个简单例子或实际应用场景。

这样会比只背概念更像真实项目型候选人。