当前位置:首页>python>Python面试精华(1):语言基础与数据结构

Python面试精华(1):语言基础与数据结构

  • 2026-09-05 19:08:41
Python面试精华(1):语言基础与数据结构

Python编程基础·面试精华(上):语言基础与数据结构

第1章 编程基础:Python · Part 1/5

涵盖Python语言基础(8问)与Python数据结构(8问),共16个高频面试问答。

2026校招又快开始了,校招算法岗面试,Python 是绕不开的第一关。网上"Python面试题"一搜一大把,但要么只有答案没解释,要么东拼西凑不成体系。这个系列从面试官视角出发,每题先给答案、再拆原理、最后附面试追问,帮你从"能回答"升级到"能讲透"。

第一篇从语言基础和数据结构开始,共 16 个高频问答。


一、Python语言基础

1. Python是解释语言还是编译语言?

Python通常被归类为解释型语言,但从底层实现来看,它实际上是"解释 + 编译"的混合模式。

Python的执行过程分为两步:

  1. 编译
    :Python源代码(.py)首先被编译为字节码(.pyc),这一步由Python编译器完成。
  2. 解释
    :字节码由Python虚拟机(PVM)逐条解释执行。

因此,Python本质上是一种"编译到字节码的执行方式",这与纯解释型语言(如Shell脚本,逐行解析执行)不同。

解释型语言的优点是可移植性好(一次编写,到处运行),缺点是运行速度通常比编译型语言慢。

编译型语言(如C/C++)直接将源代码编译为机器码,运行速度快,但可移植性较差,需要针对不同平台重新编译。

为什么它依然被定义为"解释型语言"?

虽然有编译的过程,但计算机科学界普遍仍将 Python 划分为解释型语言,原因在于:

  1. 没有生成独立的机器码文件
    :Python 编译出的 .pyc 字节码不是直接给 CPU 运行的二进制程序,依然需要依赖 Python 解释器(PVM)才能运行。而 C/C++ 编译出的 .exe/.out 文件可以直接在操作系统上独立执行。
  2. 具备动态语言特征
    :Python 的类型检查、内存管理和变量绑定都是在程序运行期间(Runtime)由解释器动态完成的,这与 C/C++ 等在编译期就固定好一切的纯编译型语言有本质区别。

补充:通过JIT(Just-In-Time)编译器(如PyPy、Numba),Python可以进一步将热点字节码编译为机器码,大幅提升运行效率。


2. Python中的可变对象和不可变对象?

可变对象与不可变对象的区别在于对象本身的值是否可以被修改。

类型
示例
可变对象list
(列表)、dict(字典)、set(集合)、bytearray(字节数组)
不可变对象int
(整型)、float(浮点型)、bool(布尔型)、str(字符串)、tuple(元组)、frozenset(冻结集合)、bytes(字节)

关键理解:

  • 对不可变对象的"修改"操作实际上会创建一个新对象。
  • 对可变对象的修改是在原对象上进行的。
PYTHON

# 不可变对象:看似修改,实为创建新对象

a = "hello"

print(id(a))        # 例如:140234567890

a = a + " world"

print(id(a))        # 不同了!是新对象

# 可变对象:原地修改

lst = [1, 2, 3]

print(id(lst))      # 例如:140234567891

lst.append(4)

print(id(lst))      # 同一个id!


3. Python中None代表什么含义?

None 是Python中的一个特殊常量,属于 NoneType 类型,表示"没有值"或"空值"。

核心特性:

  • None
     是全局唯一的单例对象,所有 None 都指向同一个对象。
  • None
     在布尔上下文中被视为 False。
  • 判断一个变量是否为 None 应使用 is 而非 ==。

常见用法:

PYTHON

# 1. 函数无返回值时默认返回None

def no_return():

pass

print(no_return())  # None

# 2. 作为默认参数

def process(data=None):

if data isNone:

        data = []

return data

# 3. 表示查找失败

def find(items, target):

for item in items:

if item == target:

return item

returnNone

# 4. 正确判断方式

a = None

if a isNone:      # ✅ 推荐

print("a isNone")

if a == None:      # ⚠️ 可行但不推荐(可能被自定义__eq__覆盖)

print("a equals None")

None vs 空值:None 表示"没有值",而 ""(空字符串)和 [](空列表)表示"值是空的",二者在语义上不同。


4. Python中is和==的区别?

运算符
比较内容
说明
is对象身份
(id())
判断两个引用是否指向同一个内存对象
==对象值
(value)
判断两个对象的值是否相等(调用 __eq__ 方法)
PYTHON

a = [1, 2, 3]

b = [1, 2, 3]

c = a

print(a == b)   # True  (值相等)

print(a is b)   # False (不同对象)

print(a is c)   # True  (同一对象)

关于整数和字符串的"缓存"陷阱:

Python会缓存小整数(-5到256)和部分短字符串,使得它们的 is 比较碰巧为 True,但这不是语言规范保证的行为,不应依赖:

PYTHON

a = 256

b = 256

print(a is b)   # True(在缓存范围内)

a = 257

b = 257

print(a is b)   # 可能为False!(超出缓存范围,行为取决于实现)

总结:除非明确要判断是否为同一对象(如 is None),否则应使用 == 进行值比较。


5. Python中type()和isinstance()的区别?

函数
作用
是否考虑继承
type()
返回对象的确切类型
❌ 不考虑
isinstance()
判断对象是否为指定类型(或其子类)
✅ 考虑
PYTHON

class Animal:

pass

class Dog(Animal):

pass

dog = Dog()

print(type(dog) == Dog)        # True

print(type(dog) == Animal)     # False(不认父类)

print(isinstance(dog, Dog))    # True

print(isinstance(dog, Animal)) # True(识别继承关系)

# isinstance 支持多类型检查

print(isinstance(42, (int, float, str)))  # True

使用建议:在需要检查类型时,优先使用 isinstance(),它在面对继承和多态时更加健壮。


6. Python中全局变量与局部变量之间的区别?

维度
全局变量
局部变量
定义位置
函数/类外部
函数/代码块内部
作用域
整个模块
定义它的函数或代码块内
生命周期
随模块存在
函数调用结束即销毁
访问方式
函数内可直接读取
仅限局部访问

在函数内修改全局变量必须使用 global 关键字,否则Python会创建一个同名的局部变量:

PYTHON

x = 10  # 全局变量

def update():

global x      # 声明要修改的是全局变量

    x = 20

def bad_update():

    x = 30        # 这创建了一个新的局部变量,不会影响全局x!

update()

print(x)  # 20

bad_update()

print(x)  # 仍然是20

对于嵌套函数中修改外层(非全局)变量,使用 nonlocal 关键字:

PYTHON

def outer():

    count = 0

def inner():

nonlocal count

        count += 1

return count

return inner


7. Python中`if __name__ == '__main__'`的作用?

这个语句用于判断当前脚本是被直接运行还是被其他脚本导入。

  • 当脚本被直接运行时,__name__ 的值为 '__main__',条件成立。
  • 当脚本被其他模块 import 时,__name__ 的值为该模块的名字,条件不成立。
PYTHON

# example.py

def my_function():

print("This function is defined in the module.")

if __name__ == '__main__':

    # 只有直接运行 example.py 时才会执行

    my_function()

典型用途:

  1. 在模块中放置测试代码,直接运行时测试,被导入时不执行。
  2. 将脚本的"入口点"与可复用的函数/类分离。

8. Python中assert的作用?

assert 用于调试阶段的断言检查。当条件为 False 时,抛出 AssertionError 异常。

PYTHON

# 基本语法

assert condition, "可选的错误消息"

# 示例:验证函数输入

def print_inverse(number):

assert number > 0, "The number must be positive"

print(1 / number)

print_inverse(5)   # 正常

print_inverse(-1)  # AssertionError: The number must be positive

重要注意事项:

  • assert
     可以被全局优化选项 -O 禁用。在 python -O 模式下运行时,所有 assert 语句都会被跳过。
  • 不要用 assert 做生产环境的数据验证
    ,因为它可能被禁用。生产环境应使用显式的 if/raise 异常处理。
  • assert
     适合在开发和测试阶段快速捕获逻辑错误。

二、Python数据结构

9. Python中有哪些内建数据类型?

Python的内建数据类型可分为以下几大类:

类别
类型
是否可变
示例
None类型NoneType
不可变
None
数值类型int
、float、complex
不可变
42
、3.14、3+4j
序列类型str
、list、tuple、range
str/tuple/range不可变,list可变
"hello"
、[1,2,3]、(1,2)、range(10)
集合类型set
、frozenset
set可变,frozenset不可变
{1,2,3}
、frozenset([1,2])
映射类型dict
可变
{'key': 'value'}
布尔类型bool
不可变
True
、False
二进制类型bytes
、bytearray、memoryview
bytes不可变,bytearray可变
b'hello'

选型建议:

  • 需要键值映射 → dict
  • 需要有序、可修改的集合 → list
  • 需要不可修改的有序集合(如作为dict的key)→ tuple
  • 需要去重和集合运算 → set
  • 需要高效查找 → set 或 dict(O(1)平均复杂度)

10. Python中列表和元组的区别?

维度
列表(list)
元组(tuple)
可变性
可变,可增删改
不可变,创建后不能修改
语法[1, 2, 3](1, 2, 3)
内存
分配空间更大(预留扩容)
更小(固定大小)
性能
略慢
更快(无修改开销)
可作为dict的key
❌
✅
适用场景
同质、可变数据集合
异构、固定数据(如坐标、配置)
PYTHON

# 列表可变

lst = [1, 2, 3]

lst[0] = 10      # ✅ OK

# 元组不可变

tup = (1, 2, 3)

# tup[0] = 10   # ❌ TypeError

# 元组作为字典键

locations = {(0, 0): "origin", (1, 0): "right"}


11. Python中dict(字典)的底层结构?

Python字典使用哈希表作为底层实现,平均查找、插入、删除时间复杂度均为 O(1)。

CPython的实现演进:

Python 3.6之前:使用单一稀疏哈希表,每个槽位存储 (hash, key, value) 三元组。通过开放寻址法的伪随机探查(pseudo-random probing)解决哈希冲突。稀疏表内存利用率不高。

Python 3.6+:Raymond Hettinger 提出紧凑字典(compact dict),核心创新是将索引与条目分离存储:

  • dk_indices
    :稀疏的索引数组(存储条目在 entries 中的位置)
  • dk_entries
    :密集的条目数组(顺序存储键值对,自然保持插入顺序)

Python 3.7+:字典正式保证插入顺序(3.6是CPython实现细节,3.7成为语言规范)。

PYTHON

d = {'a': 1, 'b': 2, 'c': 3}

# Python 3.7+ 保证遍历顺序为 a → b → c

for k in d:

print(k)    # a, b, c

注意事项:

  • 字典的key必须是可哈希(hashable)的,即不可变类型(str、int、tuple等);list和dict不能作为key。
  • 负载因子达到 2/3 阈值时会触发 rehash 扩容(USABLE_FRACTION 宏控制,例如 8 槽表在第 6 个元素插入时触发扩容)。

12. Python中的推导式?

推导式(Comprehensions)是Python中一种简洁、高效地构建数据结构的语法。共有四种:

列表推导式(List Comprehension)

PYTHON

# 语法:[expression for item in iterable if condition]

squares = [x**2 for x inrange(10)]

print(squares)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 带条件过滤

even_squares = [x**2 for x inrange(10) if x % 2 == 0]

print(even_squares)  # [0, 4, 16, 36, 64]

字典推导式(Dict Comprehension)

PYTHON

# 语法:{key_expr: value_expr for item in iterable if condition}

squares_dict = {x: x**2 for x inrange(5)}

print(squares_dict)  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

集合推导式(Set Comprehension)

PYTHON

# 语法:{expression for item in iterable if condition}

# 注意:结果自动去重

square_set = {x**2 for x inrange(-5, 5)}

print(square_set)  # {0, 1, 4, 9, 16, 25}

生成器推导式(Generator Expression)

PYTHON

# 语法:(expression for item in iterable if condition)

# 注意:圆括号,惰性求值,节约内存

square_gen = (x**2 for x inrange(10))

print(square_gen)  # <generator object <genexpr> at 0x...>

print(list(square_gen))  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

性能提示:列表推导式通常比等价的 for 循环 + append 更快,因为它在C层面执行循环。


13. Python中常见的切片操作

切片语法:sequence[start:stop:step]

  • start
    :起始索引(包含),默认0
  • stop
    :结束索引(不包含),默认序列长度
  • step
    :步长,默认1;负值表示反向
PYTHON

example = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 基本操作

example[:6]     # [1, 2, 3, 4, 5, 6]   前6个

example[6:]     # [7, 8, 9, 10]         从第7个到末尾

example[1:]     # [2, 3, 4, 5, 6, 7, 8, 9, 10]  从第2个到末尾

example[:-1]    # [1, 2, 3, 4, 5, 6, 7, 8, 9]   除最后一个

example[-1]     # 10                      最后一个元素

example[::-1]   # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]  反转列表

example[2:7:2]  # [3, 5, 7]               步长为2

example[4::-1]  # [5, 4, 3, 2, 1]         从索引4开始反向


14. Python中互换变量有不用创建临时变量的方法吗?

有,利用Python的元组打包与解包:

PYTHON

x, y = y, x

原理:

  1. 右侧 y, x 先求值,创建一个临时元组 (y原值, x原值)
  2. 通过解包(unpacking),将元组元素分别赋给左侧的 x 和 y

这种写法简洁且Pythonic,也适用于多变量交换:

PYTHON

a, b, c = c, a, b


15. Python中index使用注意事项

list.index(element, start, end) 返回元素在列表中首次出现的索引。

PYTHON

lst = [1, 2, 3, 2, 4]

print(lst.index(2))      # 1(首次出现的索引)

print(lst.index(2, 2))   # 3(从索引2开始找)

注意事项:

  • 只返回第一个匹配项的索引,不会返回所有位置。
  • 如果元素不存在,抛出 ValueError。
  • 在无法确定列表中元素是否唯一的情况下,建议使用 enumerate 遍历:
PYTHON

# 查找所有匹配位置

indices = [i for i, val inenumerate(lst) if val == 2]

print(indices)  # [1, 3]


16. Python中remove、del以及pop之间的区别?

方法
删除依据
返回值
说明
remove(value)
按值删除
无(None)
删除第一个匹配的值,值不存在则抛 ValueError
del
按索引删除
无
是语句而非方法,支持切片删除
pop(index)
按索引删除
返回被删除的元素
index
 可选,默认删除最后一个元素
PYTHON

a = [0, 1, 2, 1, 3]

# remove:按值删除第一个匹配项

a.remove(1)          # a → [0, 2, 1, 3]

# del:按索引删除(支持切片)

a = [0, 1, 2, 1, 3]

del a[1]             # a → [0, 2, 1, 3]

del a[1:3]           # 切片删除多个元素

# pop:按索引删除并返回

a = [0, 1, 2, 1, 3]

val = a.pop(1)       # val = 1, a → [0, 2, 1, 3]

val = a.pop()        # val = 3, a → [0, 2, 1](默认删最后一个)


算法岗校招面试系列目前规划10+ 章 50+ 篇内容,涵盖 Python、C/C++、计网、数据结构、数字图像、机器学习、深度学习、大模型、Agent、算法题等所有算法岗面试核心模块。关注本号,第一时间收到更新。

校招算法岗求职干货合集 · 第1章 编程基础:Python整理版共67个问答,本文为第 1/5 篇

📮 下期预告

下一篇:函数方法与Python高级特性

实例方法 · 类方法 · 静态方法 · 函数参数 · *args/**kwargs · lambda · 迭代器与生成器 · 装饰器 · 魔术方法 · 字符串格式化

共 14 个问答,明天见。

最新文章

随机文章