繁体   English   中英

在 Python 中创建简单的脚本语言

[英]Creating a simple scripting language in Python

我正在创建一个 GUI 应用程序,它可以监视和操作 stream 消息。 我正在尝试创建一种简单的方法来让用户编写其中一些功能的脚本,并且我正在寻找可能的候选人。 最初我想使用 XML 因为它可以自然地处理嵌入式代码:

<if>
   <condition>
      <recv>
         <MesgTypeA/>
      </recv>
   </condition>
   <loop count=10>
      <send>
         <MesgTypeB>
            <param1>12</param1>
            <param2>52</param2>
         </MesgTypeB>
      </send>
   </loop>
</if>

对于解析,我计划使用 ElementTree 并从代码中构建状态。 编写和阅读 XML 并不是最容易的事情,尤其是因为我不能假设脚本的作者会有任何经验。 我想知道是否有人在 Python 中有任何更容易读/写和处理的替代方案。 我查看了 JSON 但因为它是一个脚本,所以顺序很重要。

任何人都可以提出任何可能的替代方案吗?

谢谢。

Python本身怎么样?

例如:

>>> import code
>>> def host_func():
...     print("Hello old chap!")
...
>>> c = code.compile_command("print(\"Script says hello!\"); host_func()")
>>> exec(c)
Script says hello!
Hello old chap!

exec让您通过两个可选参数localsglobals明确说明要从主机环境中公开的内容。

在这个例子中,我明确说明了脚本可以访问的全局变量。 请注意,我可以在这里“创建”变量,或者给现有函数另一个名称。 它是一个指向函数和数据的字典。

>>> import code
>>> def secret():
...     print("What?! I don't even... get out of here.")
...
>>> def public():
...     print("Hello stranger.")
...
>>> c = code.compile_command("secret(); public()")

使用包含两个函数的全局变量调用它,指向已经存在的函数给出:

>>> exec(c, {"secret": secret, "public": public})
What?! I don't even... get out of here.
Hello stranger.

现在,当我省略secret时,脚本再也找不到它。

>>> exec(c, {"public": public})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<input>", line 1, in <module>
NameError: name 'secret' is not defined

在这里,我一起重新定义了secret

>>> exec(c, {"public": public, "secret":lambda: print("Haha! Doppelganger.")})
Haha! Doppelganger.
Hello stranger.

正如lazr在评论中提到的那样,存在安全问题。 上面的例子让脚本几乎可以做它想做的事。 在某些情况下,这是不可接受的。

有一些事情可以阻止它:

  • 中性__builtins__ ,仅允许“列入白名单”的内置函数。
  • 使导入模块变得困难。

例如,下面是你如何使用import语句(在 Py2.* builtins 中是__builtins__ ):

>>> import builtins
>>> def no_import(*args, **kwargs):
...     raise ImportError("I cannot let you do that, Dave.")
...
>>> builtins.__import__ = no_import
>>> import os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in no_import
ImportError: I cannot let you do that, Dave.

由此我们可以在 globals 参数中传递我们自己的builtins函数:

>>> import code
>>> evil_code = "import os; import stat; os.chmod(\"passwords.txt\", stat.S_IROT
H);"
>>> compiled = code.compile_command(evil_code)
>>> def no_import(*args, **kwargs):
...    raise ImportError("I cannot let you do that, Dave.")
...
>>> exec(compiled, {"__builtins__": {"__import__": no_import}})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<input>", line 1, in <module>
  File "<stdin>", line 2, in no_import
ImportError: I cannot let you do that, Dave.

但是,需要注意的是,这将阻止其后发生的所有导入。 将它替换为允许您导入白名单模块的版本可能会更好。

最后,我不确定这是否完全保护你。 一些狡猾的人很可能会绕过它。 但至少应该阻止最公然的违规行为。

您可以使用pyparsing定义自己的脚本语言语法。

Python 或者 Lisp,因为语法很容易解析。

暂无
暂无

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

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