100道Python面试必背题目(基础理论 + 工程实践篇)
前言
Python 因其简洁的语法和强大的生态系统,在Web开发、数据科学、人工智能等领域得到了广泛应用。无论是初学者还是资深开发者,在求职面试中,扎实的Python基础和丰富的工程实践经验都是不可或缺的。本文整理了100道Python面试中常见的问题,分为“基础理论篇”和“工程实践篇”,希望能帮助你系统地复习知识,从容应对面试挑战。
第一部分:基础理论篇
数据类型与变量
1. Python中有哪些基本数据类型?
- 数字(Number):
int,float,complex(复数)。 - 字符串(String):
str。 - 列表(List):
list。 - 元组(Tuple):
tuple。 - 字典(Dictionary):
dict。 - 集合(Set):
set。 - 布尔值(Boolean):
bool(True,False)。 - 空值(NoneType):
None。
2. 什么是可变对象和不可变对象?各举几个例子。
- 不可变对象 (Immutable): 对象一旦创建,其值就不能被修改。如果尝试修改,会创建一个新的对象。例如:
int,float,str,tuple。 - 可变对象 (Mutable): 对象创建后,其值可以被修改,而不会创建新的对象。例如:
list,dict,set。
3. list 和 tuple 的区别是什么?
- 可变性:
list是可变的,tuple是不可变的。 - 性能:
tuple作为不可变对象,通常比list占用更少的内存,并且在创建和访问时速度更快。 - 用途:
list用于需要增删改的数据集合;tuple用于存储不希望被修改的数据,例如作为字典的键。
4. dict 的底层实现原理是什么?
Python的字典(dict)是基于哈希表(Hash Table)实现的。它通过哈希函数将键(key)映射到一个唯一的索引(哈希值),然后将值(value)存储在该索引位置。这使得字典在平均情况下的插入、删除和查找操作的时间复杂度都为 O(1)。
5. set 的底层实现原理是什么?它有什么特点?
set 也是基于哈希表实现的,但它只存储键,不存储值。
- 特点:
- 元素唯一,不重复。
- 无序。
- 高效的成员检测、交集、并集、差集等操作。
6. is 和 == 的区别是什么?
==比较的是两个对象的值是否相等。is比较的是两个对象的内存地址是否相同,即它们是否是同一个对象。
7. 解释Python中的深拷贝和浅拷贝。
- 浅拷贝 (Shallow Copy): 创建一个新对象,但它只复制了原始对象的引用。如果原始对象中包含可变对象(如列表),修改其中一个会影响另一个。
copy.copy()实现。 - 深拷贝 (Deep Copy): 创建一个全新的、独立的对象,递归地复制原始对象及其包含的所有子对象。修改新对象不会影响原始对象。
copy.deepcopy()实现。
8. *args 和 **kwargs 是什么?如何使用?
它们用于函数定义中,处理不定数量的参数。
*args: 将接收到的多个位置参数打包成一个元组(tuple)。**kwargs: 将接收到的多个关键字参数打包成一个字典(dict)。
def example_func(*args, **kwargs):
print("Positional args:", args)
print("Keyword args:", kwargs)
example_func(1, 2, 'a', name='Alice', age=30)
# Output:
# Positional args: (1, 2, 'a')
# Keyword args: {'name': 'Alice', 'age': 30}
9. Python中的字符串格式化有哪几种方式?
%操作符 (旧式)。str.format()方法。- f-string (格式化字符串字面值,Python 3.6+,推荐使用)。
10. 解释一下Python的切片操作。
切片用于从序列(如列表、字符串、元组)中获取一个子序列。语法是 [start:stop:step]。
start: 起始索引(包含)。stop: 结束索引(不包含)。step: 步长。
11. 如何高效地拼接字符串? (+ vs join)
当拼接大量字符串时,应使用 str.join() 方法。因为它只需要一次内存分配,而使用 + 会在每次拼接时都创建新的字符串对象,导致性能低下。
12. 字典的 get() 方法和直接用 [] 访问有什么区别?
[]: 如果键不存在,会抛出KeyError异常。get(key, default=None): 如果键不存在,会返回指定的默认值(默认为None),而不会报错。
13. None 是什么?它和 False, 0, '' 有什么关系?
None 是一个特殊的常量,表示空值或不存在的值。在布尔上下文中,None, False, 0, '' (以及其他空集合) 都被认为是 “假” (Falsy) 的,但它们是不同的对象,None != False。
14. 什么是f-string?它有什么优点?
f-string 是 Python 3.6 引入的一种字符串格式化方式。
- 优点: 语法更简洁、可读性更高、执行速度更快,因为它在运行时直接解析表达式。
15. 如何对一个列表进行去重?
最简单的方法是将其转换为集合再转回列表:unique_list = list(set(original_list))。这种方法不保证原始顺序。如果需要保持顺序,可以使用 dict.fromkeys() 或循环。
16. Python中如何实现一个字典的有序性?
从 Python 3.7 开始,内置的 dict 类型默认就是有序的(按插入顺序)。在早期版本中,可以使用 collections.OrderedDict。
17. 解释 collections 模块中的 defaultdict 和 Counter。
defaultdict: 当访问一个不存在的键时,它会自动创建一个默认值(由工厂函数指定),而不是抛出KeyError。Counter: 一个特殊的字典子类,用于计数可哈希对象。键是元素,值是元素的数量。
18. 什么是哈希(hashable)?为什么字典的键必须是可哈希的?
一个对象是可哈希的,如果它有一个在其生命周期内永不改变的哈希值(需要 __hash__ 方法),并且可以与其他对象进行比较(需要 __eq__ 方法)。不可变对象(如 str, int, tuple)是可哈希的。字典的键必须可哈希,因为字典的底层实现依赖哈希表来快速查找键。
19. bytes 和 str 的区别是什么?
str: Unicode 字符串,用于表示文本。bytes: 字节序列,用于表示二进制数据(如图片、文件)。str通过编码(encode)可以转换为bytes,bytes通过解码(decode)可以转换为str。
20. 如何创建一个只包含唯一元素的列表?
利用 set 的特性:my_list = list(set([1, 2, 2, 3, 1]))。
函数与控制流
21. 什么是装饰器(Decorator)?请写一个简单的装饰器例子。
装饰器是一个函数,它接收另一个函数作为参数,并返回一个新的函数,通常用于在不修改原函数代码的情况下为其增加额外的功能。
import time
def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Function {func.__name__} took {end_time - start_time:.4f} seconds")
return result
return wrapper
@timer_decorator
def some_task():
time.sleep(1)
some_task()
22. 什么是生成器(Generator)?它和普通函数有什么区别?
生成器是一种特殊的迭代器,它使用 yield 关键字返回值。
- 区别:
- 普通函数使用
return返回值并终止。 - 生成器函数使用
yield“产出” 一个值并暂停执行,下次调用时从暂停处继续。这使得生成器能够按需生成值,非常节省内存。
- 普通函数使用
23. 什么是迭代器(Iterator)?
迭代器是一个对象,它实现了迭代器协议,即包含 __iter__() 和 __next__() 方法。它允许你逐个遍历一个容器中的所有元素,而无需一次性将所有元素加载到内存中。
24. yield 关键字的作用是什么?
yield 用于生成器函数中。当函数执行到 yield 时,它会返回一个值给调用者并暂停执行。函数的状态(包括局部变量)会被保存,直到下一次调用 next() 时从暂停的地方恢复执行。
25. 什么是lambda函数?它有什么优缺点?
lambda 函数是一种小型的匿名函数,由 lambda 关键字创建。
- 优点: 语法简洁,适合用于需要一个简单函数作为参数的场景(如
map,filter)。 - 缺点: 只能包含单个表达式,不能包含复杂的逻辑或多行语句,可读性较差。
26. Python中的作用域(LEGB规则)是什么?
Python 解析变量名的顺序遵循 LEGB 规则:
- L (Local): 局部作用域,函数内部。
- E (Enclosing): 闭包函数外的函数作用域。
- G (Global): 全局作用域,模块级别。
- B (Built-in): 内置作用域,Python预定义的变量。
27. global 和 nonlocal 关键字的作用是什么?
global: 在函数内部声明一个变量为全局变量,允许修改全局作用域中的变量。nonlocal: 在嵌套函数中,用于修改外层(非全局)函数作用域中的变量。
28. 什么是闭包(Closure)?
当一个嵌套函数引用了其外部作用域中的变量时,就创建了闭包。闭包会“记住”其外部作用域的状态,即使外部函数已经执行完毕。
29. 列表推导式、字典推导式和集合推导式是什么?请举例。
它们是创建列表、字典和集合的简洁语法。
- 列表推导式:
squares = [x**2 for x in range(10)] - 字典推导式:
square_dict = {x: x**2 for x in range(5)} - 集合推导式:
square_set = {x**2 for x in range(5)}
30. map, filter, reduce 函数的作用分别是什么?
map(function, iterable): 对iterable中的每个元素应用function,返回一个包含结果的迭代器。filter(function, iterable): 过滤iterable,只保留function返回True的元素。reduce(function, iterable)(在functools模块中): 对iterable中的元素进行累积操作。
31. 什么是递归函数?使用时需要注意什么?
递归函数是指在函数体内调用自身的函数。
- 注意事项:
- 必须有一个明确的 基线条件(终止条件),否则会无限递归导致栈溢出。
- 注意性能问题,深度递归可能非常耗时且消耗大量内存。
32. Python中函数参数的传递方式是值传递还是引用传递?
Python 的参数传递方式可以理解为 赋值传递 (pass-by-assignment) 或 对象引用传递 (pass-by-object-reference)。
- 如果传递的是 不可变对象(如
int,str),表现类似于值传递。 - 如果传递的是 可变对象(如
list,dict),在函数内部修改该对象会影响到原始对象,表现类似于引用传递。
33. 什么是匿名函数?
即 lambda 函数,没有正式名称的函数。
34. pass 语句的作用是什么?
pass 是一个空操作语句,用作占位符。当语法上需要一个语句但程序上不需要任何操作时使用,例如在定义一个空类或函数时。
35. 如何处理Python中的异常?(try...except...finally)
try: 包含可能引发异常的代码块。except: 如果try块中发生特定类型的异常,则执行该块。else: 如果try块中没有发生异常,则执行该块。finally: 无论是否发生异常,该块中的代码总会被执行,通常用于资源清理。
面向对象编程 (OOP)
36. 解释一下Python中的类(Class)和对象(Object)。
- 类 (Class): 是创建对象的蓝图或模板,定义了一组属性和方法。
- 对象 (Object): 是类的实例,是具体的、存在的数据实体。
37. __init__ 方法的作用是什么?
__init__ 是类的构造函数(或称为初始化方法)。当一个对象被创建时,它会自动被调用,用于初始化对象的属性。
38. __new__ 和 __init__ 的区别是什么?
__new__: 是一个静态方法,负责创建类的实例。它在__init__之前被调用,并且必须返回一个类的实例。__init__: 是一个实例方法,负责初始化__new__创建的实例。__new__控制对象的创建,__init__控制对象的初始化。
39. 什么是继承?Python支持多重继承吗?
继承是一种机制,允许一个类(子类)继承另一个类(父类)的属性和方法。是的,Python 支持多重继承。
40. 什么是MRO(方法解析顺序)?
MRO (Method Resolution Order) 是 Python 在多重继承中查找方法的顺序。Python 使用 C3 线性化算法来确定这个顺序,保证每个类只被访问一次,并维护了继承图的局部优先顺序。可以通过 ClassName.mro() 查看。
41. 什么是封装、继承和多态?
- 封装: 将数据(属性)和操作数据的方法捆绑在一起,并对外部隐藏对象的内部细节。
- 继承: 子类可以继承父类的属性和方法,实现代码复用。
- 多态: 不同的对象可以对同一个消息(方法调用)做出不同的响应。例如,不同的类可以有同名的方法,但实现不同。
42. Python中的 super() 是如何工作的?
super() 用于调用父类的方法。它会根据 MRO 查找顺序,找到当前类的下一个类,并调用其方法。这在处理多重继承时非常有用。
43. 什么是类方法(@classmethod)、静态方法(@staticmethod)和实例方法?
- 实例方法: 第一个参数是
self(实例对象),只能由实例调用。 - 类方法: 第一个参数是
cls(类对象),使用@classmethod装饰器。可以由类或实例调用。 - 静态方法: 没有
self或cls参数,使用@staticmethod装饰器。它与类或实例的状态无关,本质上是一个放在类命名空间下的普通函数。
44. Python中的私有变量(__private)是真的私有吗?
不是。以双下划线 __ 开头的变量会被解释器进行“名称改写”(Name Mangling),变为 _ClassName__variable 的形式。这是一种约定,用于避免子类意外覆盖父类的属性,但仍然可以从外部访问。
45. 什么是鸭子类型(Duck Typing)?
“如果它走起来像鸭子,叫起来也像鸭子,那么它就是一只鸭子。” 鸭子类型关注的是对象的行为而不是其类型。只要一个对象有某个方法或属性,就可以被当作特定类型的对象来使用,而无需关心它的实际类继承关系。
46. 什么是魔术方法(Magic Methods)?请举例说明。
魔术方法是以双下划线开头和结尾的特殊方法,用于实现 Python 的内置功能。例如:
__init__: 构造函数。__str__: 定义str(obj)的行为。__repr__: 定义repr(obj)的行为,用于调试。__len__: 定义len(obj)的行为。
47. __slots__ 的作用是什么?
__slots__ 用于限制类实例能拥有的属性。通过将属性名定义在一个元组中,可以:
- 节省内存: Python 不会为每个实例创建
__dict__来存储属性。 - 加快属性访问速度。
- 缺点: 实例不能再动态添加
__slots__中未定义的属性。
48. 什么是 Mixin 类?
Mixin 是一种类,它为其他类提供特定的功能,但本身不打算被实例化。它通常用于多重继承中,向子类“混入”一组方法。
49. 什么是属性(Property)?如何使用 @property 装饰器?
@property 装饰器可以将一个方法转换为只读属性,让你可以在不改变接口的情况下添加额外的逻辑(如计算或验证)。可以配合 @*.setter 和 @*.deleter 来控制属性的修改和删除。
50. 抽象基类(ABC)是什么?如何使用?
抽象基类(Abstract Base Class)是一种不能被实例化的类,用于定义接口。它强制子类必须实现某些特定的方法。通过 abc 模块和 @abstractmethod 装饰器来实现。
模块与内存管理
51. Python的模块(Module)和包(Package)有什么区别?
- 模块: 一个
.py文件就是一个模块。 - 包: 一个包含
__init__.py文件的目录。包是组织模块的一种方式。
52. __init__.py 文件的作用是什么?
- 标识包: 它的存在告诉 Python 该目录应被视为一个包。
- 初始化: 可以在该文件中编写包级别的初始化代码。
- 简化导入: 可以使用
__all__变量控制from package import *的行为。
53. 如何解决循环导入(Circular Import)的问题?
- 重构代码: 将共享的依赖项移到第三方模块中。
- 延迟导入: 在函数或方法内部进行导入,而不是在模块顶部。
- 使用
import ... as ...,并在需要时引用。
54. Python的垃圾回收机制(Garbage Collection)是怎样的?
Python 主要使用 引用计数 为主的垃圾回收机制,并辅以 标记-清除 和 分代回收 来解决循环引用的问题。
- 引用计数: 每个对象都有一个引用计数器。当计数器变为 0 时,对象被回收。
- 标记-清除: 用于检测循环引用。它会从根对象开始遍历,标记所有可达对象,然后清除未被标记的对象。
- 分代回收: 将对象分为三代(年轻代、中年代、老年代)。垃圾回收主要在新对象上进行,因为大多数对象生命周期很短。
55. 什么是引用计数?它有什么缺点?
- 机制: 跟踪每个对象的引用数量。当引用被创建时+1,被销毁时-1。当计数为0时,回收对象。
- 缺点: 无法处理 循环引用(例如,两个对象互相引用)。
56. 什么是分代回收?
一种优化策略。它基于这样一个假设:大多数对象的生命周期都很短。因此,将对象按“年龄”分为不同的代。垃圾回收器会更频繁地扫描年轻代,从而提高效率。
57. 什么是GIL(全局解释器锁)?它对Python多线程有什么影响?
GIL (Global Interpreter Lock) 是一个互斥锁,它保证在任何时刻,只有一个线程在执行 Python 字节码。
- 影响: 这意味着在 CPython 解释器中,即使在多核 CPU 上,Python 的多线程也无法实现真正的并行计算,因此不适合 CPU密集型 任务。但对于 I/O密集型 任务,当一个线程等待 I/O 时,GIL 会被释放,允许其他线程运行,从而提高效率。
58. 为什么说Python的多线程不适合CPU密集型任务?
因为 GIL 的存在,多线程在同一时间只能利用一个 CPU 核心。对于需要大量计算的 CPU 密集型任务,多线程不仅不能提高速度,反而会因为线程切换的开销而变慢。这类任务应使用多进程(multiprocessing)。
59. 什么是猴子补丁(Monkey Patching)?
在运行时动态地修改或替换模块、类或函数的行为。这是一种强大的技术,但会降低代码的可读性和可维护性,应谨慎使用。
60. 什么是元类(Metaclass)?
元类是创建类的“类”。正如类是创建对象的模板,元类是创建类的模板。你可以通过定义元类来控制类的创建过程。type 是 Python 中最基本的元类。
第二部分:工程实践篇
Web 与框架
61. 解释一下WSGI是什么。
WSGI (Web Server Gateway Interface) 是 Python Web 应用与 Web 服务器之间的一个标准接口。它定义了一套规范,使得任何兼容 WSGI 的应用(如 Django, Flask)都可以运行在任何兼容 WSGI 的服务器(如 Gunicorn, uWSGI)上。
62. Django 和 Flask 的区别是什么?
- Flask: 是一个微框架,核心简单,高度可扩展。它不自带 ORM、表单验证等功能,需要通过第三方库实现。适合小型项目或需要高度定制化的项目。
- Django: 是一个“全家桶”框架,自带了 ORM、Admin后台、表单、认证等大量组件。遵循“约定优于配置”,开发效率高。适合大型、复杂的项目。
63. Django的MVT和MVC模式有什么关系?
Django 的 MVT 模式是 MVC 模式的一种变体。
- Model (模型): 对应 MVC 的 Model,负责数据层。
- View (视图): 对应 MVC 的 Controller,负责业务逻辑。
- Template (模板): 对应 MVC 的 View,负责展示层。
64. 什么是Django的中间件(Middleware)?它的作用是什么?
中间件是一个轻量级的插件系统,用于在请求-响应处理的各个阶段介入并执行自定义逻辑。常见用途包括:用户认证、CSRF保护、会话管理、日志记录等。
65. Django ORM中 select_related 和 prefetch_related 的区别?
两者都用于优化数据库查询,解决 N+1 查询问题。
select_related: 通过 SQLJOIN来获取关联的 一对一 或 多对一 关系的对象。它在一次查询中获取所有数据。prefetch_related: 对于 多对多 或 一对多 关系,它会单独执行一次查询来获取关联对象,然后在 Python 层面进行“连接”。
66. 什么是RESTful API?设计时应遵循哪些原则?
RESTful 是一种 API 设计风格,它使用 HTTP 协议的标准方法来操作资源。
- 原则:
- 资源 (Resource): API 操作的对象,用 URL 标识。
- 统一接口 (Uniform Interface): 使用 HTTP 方法 (
GET,POST,PUT,DELETE) 对资源进行操作。 - 无状态 (Stateless): 服务器不保存客户端的状态,每个请求都应包含所有必要信息。
- 客户端-服务器分离 (Client-Server)。
67. 什么是JWT(JSON Web Token)?它是如何工作的?
JWT 是一种紧凑且自包含的认证方式。一个 JWT 由三部分组成:Header、Payload、Signature。服务器通过验证签名来确认令牌的有效性,Payload 中可以包含用户信息,从而实现无状态认证。
68. Web开发中如何防止CSRF和XSS攻击?
- CSRF (跨站请求伪造):
- 使用 CSRF Token 并验证。
- 检查
Referer头。
- XSS (跨站脚本攻击):
- 对用户输入进行严格的转义和过滤。
- 设置
Content-Security-Policy(CSP) 响应头。 - 对 Cookie 设置
HttpOnly属性。
69. 解释一下Flask的上下文管理(Context)。
Flask 有两种上下文:
- 应用上下文 (Application Context): 存储与应用相关的信息,如配置。通过
current_app访问。 - 请求上下文 (Request Context): 存储与单个 HTTP 请求相关的信息,如请求对象、会话。通过
request,session访问。
70. 什么是蓝图(Blueprint)在Flask中的作用?
蓝图用于组织和模块化 Flask 应用。你可以将一组相关的视图、模板和静态文件定义在一个蓝图中,然后在主应用中注册它。这使得大型应用的管理变得更加容易。
并发与异步
71. Python中的进程(Process)和线程(Thread)有什么区别?
- 进程: 是资源分配的基本单位。每个进程有独立的内存空间,进程间通信(IPC)复杂。
- 线程: 是 CPU 调度的基本单位。线程共享所属进程的内存空间,创建和切换开销小。
- 由于 GIL 的存在,Python 的多线程不适合 CPU 密集型任务,而多进程可以利用多核 CPU。
72. 什么是协程(Coroutine)?
协程是一种用户态的轻量级线程。它的调度完全由程序控制,切换开销极小。协程在单个线程内执行,通过 async/await 在遇到 I/O 操作时主动让出控制权,实现非阻塞的并发。
73. asyncio 是如何工作的?async/await 关键字的作用是什么?
asyncio 是 Python 的异步编程库,基于事件循环(Event Loop)。
- 工作原理: 将异步任务放入事件循环中。当任务遇到 I/O 等待时,它会挂起并让出控制权,事件循环则运行其他就绪的任务。当 I/O 完成时,事件循环会唤醒之前的任务继续执行。
async: 用于定义一个协程函数。await: 用于挂起一个协程的执行,等待另一个协程完成。
74. 什么是多路复用I/O(I/O Multiplexing)?
这是一种高效的 I/O 模型,允许单个线程同时监控多个 I/O 连接。当任何一个连接准备好读/写时,操作系统会通知程序,程序再去处理。select, poll, epoll 是常见的实现方式,asyncio 底层就利用了这种模型。
75. multiprocessing 模块是如何实现多进程的?
它通过创建子进程来绕过 GIL,实现真正的并行计算。每个子进程都有自己独立的 Python 解释器和内存空间。
76. 进程间通信(IPC)有哪些方式?
multiprocessing 模块提供了多种 IPC 方式:
Queue: 进程安全的队列。Pipe: 管道,用于两个进程间的双向通信。Manager: 提供共享的数据结构,如dict,list。Value/Array: 共享内存。
77. 什么是线程安全?如何保证线程安全?
线程安全是指当多个线程访问共享资源时,不会产生不正确的结果。
- 保证方法:
- 使用锁(
threading.Lock)来保护临界区。 - 使用线程安全的数据结构(如
queue.Queue)。 - 避免共享状态。
- 使用锁(
78. 什么是死锁(Deadlock)?如何避免?
死锁是指两个或多个线程互相等待对方释放资源,导致所有线程都被阻塞。
- 避免方法:
- 按固定顺序获取锁。
- 使用超时机制。
- 死锁检测算法。
79. 什么是守护线程/进程(Daemon)?
守护线程/进程会随着主线程/进程的退出而自动退出。通常用于执行一些后台任务。可以通过 thread.daemon = True 或 process.daemon = True 设置。
80. Celery 是什么?它通常用在什么场景?
Celery 是一个强大的分布式任务队列。
- 应用场景:
- 异步任务: 将耗时的操作(如发送邮件、文件处理)放入后台执行,避免阻塞 Web 请求。
- 定时任务: 按计划执行周期性任务。
数据库与工具
81. 关系型数据库和非关系型数据库的区别是什么?
- 关系型数据库 (SQL): 数据以表格形式存储,有严格的 schema,支持复杂的查询和事务 (ACID)。例如:MySQL, PostgreSQL。
- 非关系型数据库 (NoSQL): 数据结构灵活(如键值对、文档、图),通常 schema-less,具有高可扩展性和性能。例如:Redis, MongoDB。
82. 什么是数据库索引?它的优缺点是什么?
索引是一种特殊的数据结构,用于加快数据库表的查询速度。
- 优点: 大大提高数据检索速度。
- 缺点: 占用额外的存储空间;降低插入、更新和删除的速度,因为索引也需要维护。
83. 什么是数据库事务(Transaction)?它有哪些特性(ACID)?
事务是一系列操作的集合,这些操作要么全部成功,要么全部失败。
- ACID 特性:
- 原子性 (Atomicity): 事务是不可分割的最小工作单元。
- 一致性 (Consistency): 事务使数据库从一个一致性状态转移到另一个一致性状态。
- 隔离性 (Isolation): 多个并发事务之间互不干扰。
- 持久性 (Durability): 事务一旦提交,其结果就是永久性的。
84. SQL注入是什么?如何防止?
SQL 注入是一种攻击,攻击者通过在输入中插入恶意的 SQL 代码来欺骗数据库执行非预期的命令。
- 防止方法:
- 使用参数化查询(预编译语句),永远不要手动拼接 SQL 字符串。
- 使用 ORM 框架,它们通常会自动处理参数化。
85. 什么是ORM?它有什么优缺点?
ORM (Object-Relational Mapping) 是一种将程序中的对象与关系型数据库中的表进行映射的技术。
- 优点:
- 提高开发效率,无需编写原生 SQL。
- 代码更易于维护,数据库无关性。
- 缺点:
- 性能可能不如原生 SQL。
- 对于复杂的查询,ORM 可能难以表达或效率低下。
86. pip 和 conda 的区别是什么?
pip: Python 的官方包管理器,用于安装和管理 Python 包。conda: 一个跨平台的包和环境管理器。它不仅能管理 Python 包,还能管理非 Python 的依赖(如 C/C++ 库)和 Python 解释器本身。
87. 什么是虚拟环境?为什么需要它?
虚拟环境是一个独立的 Python 运行环境,允许你在同一台机器上为不同的项目安装不同版本的依赖包。
- 为什么需要:
- 避免不同项目之间的依赖冲突。
- 保持全局 Python 环境的干净。
- 方便项目依赖的管理和迁移。
88. 解释 requirements.txt 和 setup.py 的作用。
requirements.txt: 通常用于记录一个项目的所有依赖及其精确版本,方便复现环境 (pip install -r requirements.txt)。setup.py: 用于定义一个 Python 包的元数据(如名称、版本)和依赖项。它用于打包和分发项目 (pip install .)。
89. Docker在Python开发中的作用是什么?
Docker 允许你将应用及其所有依赖(包括操作系统库)打包到一个轻量级、可移植的容器中。
- 作用:
- 确保开发、测试和生产环境的一致性。
- 简化部署流程。
- 隔离应用。
90. 什么是CI/CD?
- CI (持续集成): 开发人员频繁地将代码合并到主干。每次合并都会自动触发构建和测试,以尽早发现集成错误。
- CD (持续交付/持续部署): 在 CI 的基础上,将通过测试的代码自动部署到类生产环境(持续交付)或生产环境(持续部署)。
算法与设计
91. 请实现一个斐波那契数列函数,并考虑优化。
# 基础递归 (效率低)
def fib_recursive(n):
if n <= 1:
return n
return fib_recursive(n-1) + fib_recursive(n-2)
# 动态规划 (推荐)
def fib_dp(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
92. 请实现一个二分查找算法。
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1 # 未找到
93. 常见的排序算法有哪些?时间复杂度分别是多少?
- 冒泡排序: O(n²)
- 选择排序: O(n²)
- 插入排序: O(n²)
- 快速排序: 平均 O(n log n),最坏 O(n²)
- 归并排序: O(n log n)
- 堆排序: O(n log n)
94. 如何判断一个链表是否有环?
使用快慢指针法。设置两个指针,一个快指针每次走两步,一个慢指针每次走一步。如果链表有环,快指针最终会追上慢指针。
95. 如何翻转一个链表?
使用三个指针:prev, curr, next_node。遍历链表,依次改变每个节点的 next 指向,使其指向前一个节点。
96. 什么是PEP 8?请举例说明。
PEP 8 是 Python 的官方代码风格指南。它规定了代码的布局、命名约定、注释等。例如:
- 使用 4 个空格进行缩进。
- 行长不超过 79 个字符。
- 函数和变量名使用蛇形命名法 (
snake_case)。 - 类名使用驼峰命名法 (
CamelCase)。
97. 如何对Python代码进行性能分析(Profiling)?
可以使用内置的 cProfile 模块。它可以详细报告每个函数的调用次数和执行时间,帮助找到代码的性能瓶颈。
98. 什么是缓存(Caching)?常见的缓存策略有哪些?
缓存是将计算结果或数据临时存储起来,以便后续请求可以更快地访问。
- 常见策略:
- LRU (Least Recently Used): 替换最近最少使用的数据。
- LFU (Least Frequently Used): 替换使用频率最低的数据。
- FIFO (First-In, First-Out): 先进先出。
99. 设计一个简单的URL短链接服务。
- 核心功能: 将长 URL 转换为短 URL,并通过短 URL 重定向到原始的长 URL。
- 设计要点:
- 短码生成: 使用自增 ID 转换为 62 进制,或使用哈希算法生成。
- 存储: 使用 K-V 数据库(如 Redis)或关系型数据库存储短码和长 URL 的映射关系。
- 重定向: Web 服务器接收到短链接请求后,查询数据库找到对应的长 URL,返回 301/302 重定向。
100. 你在项目中遇到过最难的技术挑战是什么?如何解决的?
这是一个开放性问题,旨在考察你的问题解决能力、技术深度和经验。准备一个真实的项目案例,清晰地描述:
- 问题背景 (Context): 项目是什么,遇到了什么问题。
- 挑战 (Challenge): 问题的难点在哪里(性能、并发、架构等)。
- 行动 (Action): 你是如何分析、调研、并采取了哪些具体措施来解决的。
- 结果 (Result): 解决方案带来了什么效果(性能提升、问题解决等),以及你从中学到了什么。
1132

被折叠的 条评论
为什么被折叠?



