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
相关产品推荐
相关产品推荐

