Python面试题目及答案
一、基础概念题
题目:列表(list)和元组(tuple)有什么区别?实际开发中怎么选择用哪个?
答案:首先是可变性,列表是可变的,能增删改元素(比如list.append(1));元组一旦创建就不能改,除非里面嵌套了可变类型(比如元组里的列表能改)。然后是内存,元组更轻量,相同元素的元组比列表占内存少,因为列表要预留动态扩容的空间。
实际选的时候,要是数据不需要改,比如存固定的配置项(像(100,200)这种窗口尺寸)、函数返回的多个固定值,就用元组,还能避免误修改;要是数据需要动态调整,比如购物车商品列表、日志记录集合,就用列表。
题目:Python里的切片操作,比如a=[1,2,3,4,5],a[1:3]、a[:3]、a[::-1]分别得到什么?切片会修改原列表吗?
答案:a[1:3]是从索引1取到3(不包含3),结果是[2,3];a[:3]是从开头取到3,结果[1,2,3];a[::-1]是倒序取所有元素,结果[5,4,3,2,1]。
切片不会改原列表,它会生成一个新的列表/序列,所以哪怕切片后赋值给新变量,原变量里的内容也不变。比如b=a[1:3],改b的话a还是原来的样子。
二、进阶特性题
题目:什么是装饰器?举个实际开发中用装饰器的场景,再写个简单示例。
答案:装饰器本质是“包装函数的函数”,能在不修改原函数代码的前提下,给函数加额外功能(比如日志、权限校验、计时),还能保持函数调用方式不变。
实际场景比如接口请求的日志记录:每次调用接口函数,自动记录调用时间、传入参数。示例如下:
importtime
#定义装饰器
deflog_request(func):
defwrapper(*args,**kwargs):
#额外功能:记录时间和参数
now=time.strftime(%Y-%m-%d%H:%M:%S)
print(f[{now}]调用函数:{func.__name__},参数:{args},{kwargs})
#执行原函数
result=func(*args,**kwargs)
returnresult
returnwrapper
#用装饰器装饰接口函数
@log_request
defget_user(user_id):
returnf用户信息:id={user_id}
#调用函数,会自动触发日志
get_user(123)#输出:[2025-xx-xxxx:xx:xx]调用函数:get_user,参数:(123,),{},返回用户信息
题目:生成器(generator)和迭代器(iterator)有什么关系?生成器相比普通列表有什么优势?
答案:首先,生成器是迭代器的一种,它自动实现了__iter__和__next__方法,不用手动写迭代器的逻辑。
生成器的优势是省内存:普通列表会把所有元素一次性加载到内存里,比如[iforiinrange(1000000)]会占很多内存;但生成器(比如(iforiinrange(1000000))或用yield的函数)是“按需生成”,每次只生成一个元素,取完一个再生成下一个,哪怕处理千万级数据也不会占太多内存。
比如处理大文件时,用生成器逐行读取,比把整个文件读到列表里高效得多。
三、实际应用题
题目:写一段代码,读取一个文本文件(比如test.txt),统计文件里每个单词出现的次数,忽略大小写,并且排除标点符号(比如逗号、句号)。
答案:思路是先读取文件,然后处理每行内容(转小写、去掉标点),再分割成单词,最后用字典统计次数。代码如下:
importstring
defcount_words(file_path):
word_count={}
#读取文件(用with自动关闭文件,避免资源泄漏)
withopen(file_path,r,encoding=utf-8)asf:
forlineinf:
#1.转小写
line_lower=line.lower()
#2.去掉标点(把每个字符替换成空,要是字符在string.punctuation里)
line_clean=line_lower.translate(str.maketrans(,,string.punctuation))
#3.分割成单词(按空格分割