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

Sympy parse_expr解析含@字符串报TypeError的解决方案咨询

问题本质

SymPy的parse_expr默认遵循Python标准语法规则,@在Python语法中是矩阵乘法运算符,不属于合法标识符的允许字符,解析时会被自动识别为二元运算符,因此会抛出两个Symbol类型不支持@运算的错误。你当前用全局替换@为下划线的方案仅适用于简单场景,存在误替换、无法保留原始命名的问题,更合理的处理方式是自定义解析阶段的token转换规则,不需要修改原始输入字符串。

推荐方案:自定义token合并转换

利用parse_expr预留的transformations参数,注入自定义的词法处理逻辑,仅将前后都为标识符的@识别为名称的组成部分,不会干扰@作为矩阵乘法运算符的正常使用(如果后续有相关需求)。
完整可运行代码如下:

from sympy.parsing.sympy_parser import (
    parse_expr,
    Token,
    standard_transformations,
    convert_xor
)
import tokenize

def merge_at_connected_identifiers(tokens, local_dict, global_dict):
    processed_tokens = []
    idx = 0
    token_len = len(tokens)
    while idx < token_len:
        # 匹配 标识符 + @ + 标识符 的结构
        if (idx + 2 < token_len
            and tokens[idx].type == tokenize.NAME
            and tokens[idx+1].type == tokenize.OP
            and tokens[idx+1].string == "@"
            and tokens[idx+2].type == tokenize.NAME):
            # 合并连续的@连接标识符,支持a@b@c这类多段命名
            merged_name = f"{tokens[idx].string}@{tokens[idx+2].string}"
            idx += 3
            while idx + 1 < token_len and tokens[idx].type == tokenize.OP and tokens[idx].string == "@" and tokens[idx+1].type == tokenize.NAME:
                merged_name += f"@{tokens[idx+1].string}"
                idx += 2
            processed_tokens.append(Token(tokenize.NAME, merged_name))
        else:
            processed_tokens.append(tokens[idx])
            idx += 1
    return processed_tokens

# 加载默认转换规则 + 自定义@合并规则
custom_transforms = standard_transformations + (merge_at_connected_identifiers,)
# 解析表达式
expr = parse_expr(
    "abc@mmw * 2 * 5",
    transformations=custom_transforms
)
print(expr)  # 输出结果: 10*abc@mmw
方案优势
  • 不需要修改原始输入字符串,可完整保留带@的原始命名
  • 识别逻辑更严谨:仅当@两侧都是合法标识符时才会合并为名称,如果后续需要在表达式中使用@做矩阵乘法(比如M@N形式的矩阵运算),不会出现误识别
  • 如果abc@mmw是你自定义的函数,只需要在parse_expr调用时传入local_dict参数做映射即可,不需要修改本地函数的命名(Python本身不支持标识符带@),示例:
# 本地定义的函数用合法命名即可
def abc_mmw(x):
    return x ** 2

expr = parse_expr(
    "abc@mmw(2) * 2 * 5",
    transformations=custom_transforms,
    local_dict={"abc@mmw": abc_mmw}
)
print(expr) # 输出结果: 40
临时替换方案的适用场景

如果你所有待解析的表达式中都不需要用@作为矩阵乘法运算符,且不需要保留原始带@的命名,直接提前替换@为下划线的方案代码量最低,可满足简单场景需求,只是鲁棒性不如自定义转换规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 21:36:14