面试题答案
一键面试设计思路
- 数据结构:
- 使用列表来存储Python代码的每一行内容,方便按行处理。
- 可以使用栈来跟踪缩进层次,在Python中,每遇到一个新的代码块(如函数定义、循环等),缩进层次增加;代码块结束,缩进层次减少。
- 算法:
- 逐行读取Python代码。
- 计算每行代码的缩进量(通常以空格数或制表符数衡量)。
- 利用栈来维护当前的缩进层次,遇到缩进增加的行,将新的缩进层次压入栈;遇到缩进减少的行,检查栈顶元素是否匹配当前缩进减少的量,如果不匹配则说明缩进错误。
- 当遇到代码块开始的语句(如
def
、if
、for
等),记录其缩进量;遇到代码块结束的标志(如else
、elif
、finally
等),检查其缩进量是否与预期一致。
- 与Python代码解析相结合:
- 利用Python的内置模块
tokenize
来解析Python代码的词法单元。tokenize
模块可以将Python代码分解为一个个的词法单元,包括关键字、标识符、操作符等,这样能更准确地判断代码块的开始和结束,而不仅仅依赖于缩进。 - 通过分析词法单元序列,结合缩进量的计算,来全面检查缩进是否符合Python语法规则。
- 利用Python的内置模块
关键代码示例
import tokenize
from io import BytesIO
def check_indentation(code):
stack = [0] # 初始缩进层次为0
last_token_type = None
last_indent = 0
for token_type, token, start, end, line in tokenize.tokenize(BytesIO(code.encode('utf-8')).readline):
current_indent = len(line) - len(line.lstrip())
if token_type == tokenize.INDENT:
stack.append(current_indent)
elif token_type == tokenize.DEDENT:
if not stack or current_indent != stack.pop():
raise IndentationError("Unexpected dedent")
if token_type in (tokenize.NAME, tokenize.KEYWORD):
if token in ('def', 'class', 'if', 'for', 'while', 'try'):
last_token_type = token_type
last_indent = current_indent
elif token in ('else', 'elif', 'finally'):
if last_token_type not in (tokenize.KEYWORD, tokenize.NAME) or current_indent != last_indent:
raise IndentationError(f"Invalid indentation for {token}")
if stack:
raise IndentationError("Unclosed block")
return True
你可以使用以下方式调用这个函数:
code = """
def test():
print('Hello')
"""
try:
check_indentation(code)
print("Indentation is correct")
except IndentationError as e:
print(f"Indentation error: {e}")