Python编写解释器报错'NumberNode' object is not callable 排查
问题描述
- 编写仅支持数字、四则运算的自定义编程语言解释器时,代码逻辑与教程对齐但运行抛出
TypeError - 错误调用栈最终定位到Parser类
bin_op方法内的left = func()代码行,错误提示为'NumberNode' object is not callable - 预期功能:将输入的算术表达式转换为对应抽象语法树(AST)结构,例如输入
56 + 3 * 2时应输出(INT:56, PLUS, (INT:3, MUL, INT:2)) - 项目文件结构:
basic.py:存放常量定义、错误处理类、位置追踪类、Token定义、Lexer词法分析器、AST节点类(NumberNode/BinOpNode)、Parser语法分析器、run入口函数shell.py:解释器交互入口文件
错误根因
该错误由bin_op方法的传参逻辑错误直接导致:
实现二元运算优先级解析(即递归下降逻辑中处理四则运算先乘除后加减的规则)时,通用bin_op工具方法要求传入高优先级表达式的解析函数引用作为入参;若误将函数执行后的返回值(已生成的NumberNode实例)作为参数传入,bin_op内部尝试将该节点对象作为函数调用时,就会触发「对象不可调用」的类型错误。
90%以上的复现场景为:分层调用bin_op时给解析函数加了多余的执行括号,错误示例代码如下:
# 错误写法:self.term()带括号,会立刻执行方法返回NumberNode,再把节点作为参数传入bin_op def expr(self): return self.bin_op(self.term(), (TT_PLUS, TT_MINUS)) def term(self): return self.bin_op(self.factor(), (TT_MUL, TT_DIV))
修复方案
- 定位到Parser类中所有调用
bin_op的代码位置,检查作为第一个参数传入的解析函数 - 删除解析函数名后多余的
(),确保传入的是函数引用本身,而非函数执行后的返回结果,正确调用示例:
# 正确写法:传入self.term/self.factor方法引用,由bin_op内部在需要节点时执行调用 def expr(self): return self.bin_op(self.term, (TT_PLUS, TT_MINUS)) def term(self): return self.bin_op(self.factor, (TT_MUL, TT_DIV))
- 校验
bin_op内部实现逻辑,标准可运行的bin_op代码参考如下:
def bin_op(self, func, ops): left = func() # 内部执行传入的解析函数,拿到左操作数节点 while self.current_tok.type in ops: op_tok = self.current_tok self.advance() right = func() # 解析拿到右操作数节点 left = BinOpNode(left, op_tok, right) return left
修复完成后重新运行,输入56 + 3 * 2即可正常生成符合运算优先级的AST结构,不会再触发该类型错误。
内容的提问来源于stack exchange,提问作者Riccardo Zampieri
相关产品推荐
相关产品推荐

