2011-06-30 71 views
10

我正在創建一個GUI應用程序,它可以監視和操作消息流。我試圖創建一個簡單的方法讓用戶腳本的一些功能,我正在尋找可能的候選人。起初我想使用XML,因爲它可以自然地照顧嵌入式代碼:在Python中創建一個簡單的腳本語言

<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,但因爲它是一個腳本,所以訂單很重要。

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

謝謝。

回答

16

Python itself

例如:

>>> 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. 

由於lazyr在評論中提到有安全問題。上面的例子讓腳本幾乎可以做它想做的事情。在某些情況下,這是不可接受的。

有一些東西可以做,以阻止它:

  • 絕育__builtins__,只允許「白名單」的內置功能。
  • 難以導入模塊。

例如,這裏是你如何bork import語句(在Py2中。*內建爲__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. 

由此得出,我們可以通過在全局參數我們自己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. 

一個警告,不過,這將博克之後發生的所有進口。將它替換爲允許導入列入白名單的模塊的版本可能會更好。

最後,我不確定這會完全保護你。一些狡猾的人可能很好的規避它。但是最明顯的違規行爲至少應該是不鼓勵的。

+0

+1所以你通過了5000個榮譽里程碑。也許你應該提到一些關於安全問題的內容? 'open(「/ important/file」,「w」)。write(「stuff」)'等 –

+0

@lazyr:噢謝謝:D ...我會用蛋糕來慶祝。是的,我正在考慮這個問題。我可以補充一點。 – Skurmedel

+0

牆壁文字對我造成+400傷害。 – Skurmedel

3

Python或可能是Lisp,因爲語法很容易解析。

5

您可以用pyparsing定義您自己的腳本語言語法。

相關問題