繁体   English   中英

当我使用 discord.py 使用 ast.literal_eval 时,第 1 行出现格式错误的节点或字符串

[英]malformed node or string on line 1 when I use ast.literal_eval using discord.py

我尝试执行

import ast

ast.literal_eval('5+5')

然后我得到ValueError: malformed node or string on line 1: <ast.BinOp object at 0x70e6bd2830>

所以我尝试了另一个:

import ast

ast.literal_eval(str(5+5))

它成功地评估了它:

10

但是当我最终在实际命令$math 5+5上使用它时

@client.command()
async def math(ctx, expression):
    resp = ast.literal_eval(str(expression))
    await ctx.send(resp)

我仍然收到相同的错误: ValueError: malformed node or string on line 1: <ast.BinOp object at 0x7d05357700>出于某种原因。 我正在使用 Python 3.10.5。 我该如何解决这个问题? 任何帮助,将不胜感激。

整个代码:

import discord, ast
from discord.ext import commands

TOKEN = ""

client = commands.Bot(command_prefix="$")
prefix = client.command_prefix

def init():
    client.run(TOKEN, reconnect=False)

@client.event
async def on_connect():
    print('Connecting to server...')
    
    @client.event
    async def on_ready():
        await client.change_presence(status=discord.Status.idle)
        print('Logged in as ' + str(client.user))
        print('Prefix: ' + str(prefix))

@client.command()
async def math(ctx, expression):
    resp = ast.literal_eval(str(expression))
    await ctx.send(resp)

init()

自 python 3.7 起,您不再允许在literal_eval中进行加法。

从这个答案中找到了一些可以使用的“安全表达式”。 这是一个简单的演示:

import ast

value = input()
co = ast.parse(value, mode='eval')

for node in ast.walk(co):
    if not isinstance(node, (ast.Expression, ast.Constant, ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Mod, ast.Pow, ast.BinOp, ast.USub, ast.UAdd, ast.UnaryOp)):
        raise RuntimeError(f'Sorry! You gave an illegal syntax node: {node.__class__.__name__}')

print(eval(value))

这成功地评估了 python 中的有效数学,例如5 + 7*8 = 615 ** 7 = 78125 ,当然还有0.1 + 0.2 = 0.30000000000000004

不允许任何可能导致问题的错误操作,例如CallName (意思是variable_names_like_thisfunction() )。 如果您发现我遗漏了任何允许的操作,您可以简单地将它们添加到isinstance内的元组中以允许它们。 您可以精确地自定义允许或不允许哪些语法操作。


作为对任何想在不限制您可以使用的语法的情况下使用eval的人的公平警告,无论您的命名空间围栏如何,它都可以执行。 它获取object类,从中获取模块以获取__builtins__ ,然后获取__import__并用它做坏事。 对于更多危险,将此处的'echo hi'替换为'rm -rf /'

[v for c,v in [c for c in ''.__class__.__bases__[0].__subclasses__() if c.__name__ == 'catch_warnings'][0]()._module.__builtins__.items() if c == '__import__'][0]('os').system('echo hi')

根据文档,您遇到的错误似乎是因为:

提供的字符串或节点只能由以下 Python 文字结构组成:字符串、字节、数字、元组、列表、字典、集合、布尔值、 NoneEllipsis

所以当你这样做时:

ast.literal_eval('5+5')

问题是+这是一个BinOp (对应于错误消息的<ast.BinOp object at 0x7d05357700>部分)并且不能使用。

但是,当您这样做时:

ast.literal_eval(str(5+5))

评价顺序如下:

ast.literal_eval(str(5+5)) -> ast.literal_eval(str(10)) -> ast.literal_eval('10')

不再涉及+

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM