【问题标题】:How to tell if a single line of python is syntactically valid?如何判断单行 python 在语法上是否有效?
【发布时间】:2016-05-03 19:37:17
【问题描述】:

和这个很相似:

How to tell if a string contains valid Python code

唯一的区别是我没有给出整个程序,而是一次只对一行代码感兴趣。

正式地说,如果存在使用该特定行的任何语法上有效的 Python 程序,我们就说一行 Python 是“语法上有效的”。

例如,我想将这些识别为语法上有效的行:

for i in range(10):

x = 1

因为可以在一些语法上有效的 python 程序中使用这些行。

我想将这些行标识为语法上无效的行:

for j in range(10 in range(10(

x =++-+ 1+-

因为没有语法正确的 python 程序可以使用这些行

检查不需要太严格,只要足够好就可以过滤掉明显的虚假陈述(如上图所示)。当然,该行是作为字符串给出的。

【问题讨论】:

  • 仅供参考,x =+ 1 在语法上是有效的。它将+1 分配给x
  • 隐式行连接怎么样(这会使for j in range(10 也可能在语法上有效)
  • for j in range(10 也有效,如果下一行以): 之类的形式继续,if x < 3 也可以是多行表达式的一部分。几乎任何东西都可以是多行字符串的一部分。
  • 我认为您需要回答的问题是为什么您需要/想要这样做
  • for 在语法上仍然有效。赋值不再有效,除非它是三引号字符串或续行注释的一部分。我认为您不太了解自己要做什么。

标签: python validation


【解决方案1】:

这使用codeop.compile_command 来尝试编译代码。这与code 模块does 确定是请求另一行还是立即失败并出现语法错误的逻辑相同。

import codeop
def is_valid_code(line):
    try:
        codeop.compile_command(line)
    except SyntaxError:
        return False
    else:
        return True

可以这样使用:

>>> is_valid_code('for i in range(10):')
True
>>> is_valid_code('')
True
>>> is_valid_code('x = 1')
True
>>> is_valid_code('for j in range(10 in range(10(')
True
>>> is_valid_code('x = ++-+ 1+-')
False

我敢肯定,此时您是在说“什么给出?for j in range(10 in range(10( 应该是无效的!”这行的问题是 10() 在技术上是 语法上有效,至少根据 Python 解释器。在 REPL 中,你会得到:

>>> 10()
Traceback (most recent call last):
  File "<pyshell#22>", line 1, in <module>
    10()
TypeError: 'int' object is not callable

注意这是一个TypeError不是一个SyntaxErrorast.parse 表示它也是有效的,只是将其视为函数为 ast.Num 的调用。

这类东西在它们真正运行之前不容易被发现。 如果某种怪物设法修改了缓存的10 值(这在技术上是可能的),你也许可以做到10()。语法仍然允许。

不平衡的括号怎么办?这符合与for i in range(10): 相同的法案。此行本身无效,但可能是多行表达式中的第一行。例如,请参阅以下内容:

>>> is_valid_code('if x ==')
False
>>> is_valid_code('if (x ==')
True

第二行是True,因为表达式可以这样继续:

if (x ==
    3):
    print('x is 3!')

并且表达式将是完整的。事实上,codeop.compile_command 通过返回一个代码对象(如果它是一个有效的自包含行)来区分这些不同的情况,None 如果该行预计会继续完整的表达式,并在无效行上抛出一个SyntaxError .

但是,您也可能遇到比最初描述的要复杂得多的问题。例如,考虑行)。如果是模块的开头,或者上一行是{,则无效。但是,如果上一行是(1,2,,则完全有效。

这里给出的解决方案如果你只向前工作,并将前面的行作为上下文附加,那么这里给出的解决方案将起作用,这就是code 模块does 用于交互式会话的内容。在不考虑周围行的情况下,创建始终可以准确识别 Python 文件中是否可能存在单行的内容将非常困难,因为 Python 语法以非平凡的方式与换行符交互。该答案以给定行是否可以位于模块的开头并继续到下一行而不失败。

最好确定识别单行的目的是什么,并以不同的方式解决该问题,而不是尝试针对每种情况解决这个问题。

【讨论】:

  • 我同意你的逻辑。但是“for j in range(10 in range(10(”) 不应该是无效的,因为它有不匹配的括号(仅语法错误)吗?
  • 否,因为该行可能会继续到下一行。我会在答案中解释。
  • 听起来很合理!似乎比添加“通过”并尝试编译为 AST(另一个答案)更安全。我会用这个
  • @EvanPu 更重要的是要知道为什么需要这样做,然后尝试解决这个问题。
  • 如果你用谷歌搜索“sk_p”,我相信你会找到我的论文!
【解决方案2】:

我只是建议,不确定是否可以工作......但也许有 exectry-except 的东西?

code_line += "\n" + ("\t" if code_line[-1] == ":" else "") + "pass"
try:
    exec code_line
except SyntaxError:
    print "Oops! Wrong syntax..."
except:
    print "Syntax all right"
else:
    print "Syntax all right"

简单的线条应该引起适当的答案

【讨论】:

  • 我正要建议+= "pass" 方法。不过,您可能想.rstrip 这条线。此外,您不需要换行和缩进。
  • 执行行正在打开潘多拉的盒子。让我们看看while True: 在语法上是否有效。 import os; os.system('rm -rf /') 怎么样?
  • @JohnKugelman 是的,但这无论如何都需要进行沙盒处理。如果 OP 随机生成程序,有的可能不会停止,有的会影响环境。
  • @JohnKugelman 你是对的......但我想不出任何方法来做它不简单地制作 python 解释器......有人知道在不真正执行的情况下执行 python 代码的方法吗它?我知道的愚蠢问题,但可以对此有很大帮助
  • 这与我和我的实验室伙伴刚才讨论的类似。我将尝试这种方法并在一小时内报告。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-25
  • 2011-06-03
  • 1970-01-01
相关资源
最近更新 更多