Python 高频面试题解析:字符串处理、传参机制与闭包陷阱

七月
七月
发布时间:2026-10-13| 3人浏览过
原创

本文汇总了 Python 常见笔试面试题,涵盖字符串中数字翻倍替换、参数传递机制(值与引用)、浅拷贝与深拷贝的区别,以及一行代码实现奇数、水仙花数等技巧。重点解析了列表推导式中闭包延迟绑定导致的常见错误,并提供了生成器与默认参数两种解决方案。

字符串处理:数字翻倍替换实现

字符串处理

题目要求将字符串中的数字替换为其两倍的值,例如输入 "AS7G123m (d)F77k",期望输出 "AS14G246m (d)F154k"。

修改前:"AS7G123m (d)F77k"

修改后:"AS14G246m (d)F154k"

解题思路:首先利用正则表达式提取字符串中的所有数字,将每个数字乘以 2,随后以原数字为分隔符对字符串进行切割,得到字符列表。最后将处理后的数字与原字符列表拼接,形成最终结果。若读者有更优方案,欢迎交流分享。


import re

text = "AS7G123m (d)F77k"
nums = re.findall(r'(\d+)', text) # 取出字符串中数字
double_nums = [2 * int(i) for i in nums]  # 乘以2
the_str = [] # 字符列表
for i in nums:
  the_str.append(text.split(i, 1)[0])
  text = text.split(i, 1)[1]
result = "" # 结果
for i in range(len(double_nums)):
  result += the_str[i] + str(double_nums[i])
result += text
print(result)

Python 参数传递机制:引用传递解析

Python 传参是值传递还是引用传递?

结论是 Python 采用引用传递方式。可通过打印对象地址来验证:比较原变量 a 与函数参数 x 的内存地址,若两者一致,则证明传递的是引用。


 def f(x):
   print(id(x))
   
 
 a = 1
 print(id(a))
 f(a)
 # 140716760159264
 # 140716760159264

需要注意的是,对于不可变类型(如整数、字符串),在函数内部对其操作会创建新对象,不影响原对象;而对于可变类型(如列表),在函数内部的操作可能会直接修改原对象的值。

1)传入的参数是不可变类型:


 def f(x):
   x += "666" # 这里会创建一个新的对象
   print(x)
 
 
 s = "777" # 字符串不可变
 print(s)
 f(s)
 print(s)
 
 # 777
 # 777666
 # 777

2)传入的参数是可变类型:


def f(x):
   x.append(4) # 修改原对象的值
   print(x)
 
 
 s = [1, 2, 3] # 列表可变
 print(s)
 f(s)
 print(s)

# [1, 2, 3]
# [1, 2, 3, 4]
# [1, 2, 3, 4]

浅拷贝与深拷贝的区别

3.浅拷贝与深拷贝的那些事

在 Python 中,必须明确区分浅拷贝与深拷贝。

1)浅拷贝:创建一个新的对象,但该对象内部包含的是原对象中元素的引用。如果通过引用修改了嵌套对象,原对象也会随之改变。

2)深拷贝:创建一个新的对象,并递归复制原对象中包含的所有子对象。此时,即使修改深拷贝后的数据,也不会影响原对象。

代码示例展示了赋值、浅拷贝和深拷贝的行为。赋值操作(c = a)意味着 c 与 a 引用同一对象,对 c 的操作即是对 a 的操作。对于浅拷贝对象(b 和 d),修改其嵌套元素会影响原对象 a;而对深拷贝对象 e 的操作则与原对象 a 完全独立。


 import copy
 
 a = [1, [2], 3]
 b = a[:] # 使用切片操作,浅拷贝
 c = a # 赋值操作,即引用
 d = a.copy() # 浅拷贝
 e = copy.deepcopy(a) # 深拷贝
 
 b.append(4)
 c.append(5)
 d.append(6)
 d[1].append(2)
 e.append(7)
 e[1].append(3)
 
 print(a) # [1, [2, 2], 3, 5]
 print(b) # [1, [2, 2], 3, 4]
 print(c) # [1, [2, 2], 3, 5]
 print(d) # [1, [2, 2], 3, 6]
 print(e) # [1, [2, 3], 3, 7]

Python 一行代码技巧示例

4.Python 一行式能干嘛?

以下示例展示了 Python 一行代码的强大与简洁性。

1)一行代码输出一百以内的奇数:

print([x for x in range(100) if x % 2])

2)一行代码求水仙花数:

print([x for x in range(100, 1000) if int(str(x)[0])**3 + int(str(x)[1])**3 + int(str(x)[2])**3 == x])

3)一行代码打印九九乘法表:

print("".join(["{} * {} = {}\t".format(x, y, x * y) if x != y else "{} * {} = {}\n".format(x, y, x * y) for x in range(1, 10) for y in range(1, x + 1)]))

4)一行代码实现 IP 地址转换,如将 192.168.12.1 转换成二进制格式 0b11000000 10101000 00001100 00000001:

print("0b"+" ".join(("00000000" + bin(int(i)).replace("0b", ""))[-8:] for i in ip.split(".")))

5)一行代码求 1 到 10 的和:

from functools import reduce; print(reduce(lambda x, y: x + y, [i for i in range(1, 11)]))

闭包延迟绑定陷阱及解决方案

5.下面这段代码的结果是什么?


def mul():
return [lambda x: x * i for i in range(4)]


print([m(2) for m in mul()])

上述代码的输出结果是 [6, 6, 6, 6],而非预期的 [0, 2, 4, 6]。

该现象源于 Python 闭包的延迟绑定机制。内部函数在调用时,才会去查找其所在作用域中变量的当前值。由于 for 循环结束后变量 i 的值为 3,因此每次调用返回的函数时,i 均被解析为 3,导致最终结果为 2 * 3 = 6。

解决此问题可参考以下两种方法:

1)使用 Python 生成器。


 def mul():
   for i in range(4):
     yield lambda x: x * i
 
 
 print([m(2) for m in mul()])

2)利用默认参数在定义时绑定变量值,创造闭包。


 def mul():
   return [lambda x, i=i: x * i for i in range(4)]
 
 
 print([m(2) for m in mul()])

本文先介绍至此,后续将分享更多技术内容。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。