You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

discord.py调用ast.literal_eval报malformed node or string错误

问题根因

ast.literal_eval 仅支持解析Python原生字面量(整数、浮点数、字符串、列表、字典等固定值结构),完全不支持运算表达式解析,传入5+5这类带二元运算的内容时,解析到BinOp(二元运算)节点就会抛出你看到的报错,这是函数本身的设计限制,和Python 3.10.5版本无关。

你之前测试ast.literal_eval(str(5+5))能返回10,是因为5+5在传入str()前就被Python解释器计算成了整数10,str(10)得到的是纯数字字符串'10',属于literal_eval支持的字面量范围,和表达式计算能力没有任何关系。

接入discord.py指令后,你拿到的expression是用户输入的原始字符串'5+5',套一层str()不会改变内容,传入literal_eval自然会触发相同报错。
另外你现有指令还有个参数解析问题:没加*前缀的参数只会匹配空格分隔的第一个内容,用户输入带空格的表达式(比如$math 5 + 5)时会丢失后续内容。

可行解决方案

注意:严禁直接使用原生eval()处理用户输入,该函数会原样执行传入的任意Python代码,恶意用户输入破坏性指令可直接接管运行机器人的服务器,造成不可逆的损失。

方案1:自行实现AST安全校验逻辑

手动遍历解析后的语法树,仅放行数学运算需要的节点类型,拦截所有函数调用、属性访问等危险语法,校验通过后再执行计算:

import ast

def safe_calc(expr: str):
    # 白名单:仅允许数学运算相关的AST节点
    allowed_node_types = {
        ast.Expression, ast.Constant,
        ast.BinOp, ast.UnaryOp,
        ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Mod, ast.Pow,
        ast.USub, ast.UAdd
    }
    syntax_tree = ast.parse(expr.strip(), mode='eval')
    for node in ast.walk(syntax_tree):
        if type(node) not in allowed_node_types:
            raise ValueError(f"存在非法语法:{type(node).__name__}")
        # 仅允许数字类型的常量,拦截字符串、列表等其他内容
        if isinstance(node, ast.Constant) and not isinstance(node.value, (int, float)):
            raise ValueError("仅支持数字运算")
    # 禁用内置函数,封闭执行环境
    return eval(compile(syntax_tree, '<calc>', 'eval'), {"__builtins__": {}}, {})

替换原指令代码:

# 参数前加*,接收指令后所有输入内容作为表达式
@client.command()
async def math(ctx, *, expression):
    try:
        result = safe_calc(expression)
        await ctx.send(f"计算结果:{result}")
    except Exception as e:
        await ctx.send(f"计算失败:{str(e)}")

方案2:使用成熟的安全计算库

如果不想自行维护AST校验逻辑,可以使用专门做安全表达式计算的第三方库simpleeval,默认已经做了完整的安全拦截,支持常规数学运算:
先安装依赖:

pip install simpleeval

替换指令代码:

from simpleeval import simple_eval

@client.command()
async def math(ctx, *, expression):
    try:
        result = simple_eval(expression)
        await ctx.send(f"计算结果:{result}")
    except Exception as e:
        await ctx.send(f"计算失败:{str(e)}")

内容的提问来源于stack exchange,提问作者Ruri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 02:01:12