2010-08-19 51 views
2

我試圖使用python-daemon模塊。它提供daemon.DaemonContext類來正確地守護一個腳本。雖然我主要針對Python 2.6+,但我想保持向後兼容2.4版本。在Python 2.4中處理上下文類

Python 2.5支持從未來導入上下文,但Python 2.4沒有這樣的功能。 我想我可以抓住任何錯誤的語句引發和手動輸入和退出2.4的上下文,但我似乎無法趕上引發的SyntaxError。

有什麼辦法來完成這個顯式檢查解釋器版本的短小嗎? 下面是我想要做的和我得到的問題的要點。在現實生活中,我沒有上下文類的控制權,所以它需要工作而不會損壞原始類,即不像these ideas.

如果Python 2.4無法運行python-daemon;我至少希望能夠抓住錯誤並實施回退或其他事情。

感謝您的幫助。

#!/usr/bin/python2.4 
from __future__ import with_statement 
# with_statement isn't in __future__ in 2.4. 
# In interactive mode this raises a SyntaxError. 
# During normal execution it doesn't, but I wouldn't be able to catch it 
# anyways because __future__ imports must be at the beginning of the file, so 
# that point is moot. 


class contextable(object): 
    def __enter__(self): 
     print('Entering context.') 
     return None 
    def __exit__(self, exc_type, exc_val, exc_tb): 
     print('Exiting context.') 
     return False 

def spam(): 
    print('Within context.') 

context = contextable() 

try: 
    with context: # This raises an uncatchable SyntaxError. 
     spam() 
except SyntaxError, e: # This is how I would like to work around it. 
    context.__enter__() 
    try: 
     spam() 
    finally: 
     context.__exit__(None, None, None) 

回答

3

SyntaxError由Python的編譯器診斷爲它編譯 - 你大概是想「抓」,它從被被編譯爲同一模塊的一部分代碼(例如,這就是你在做什麼你的代碼示例),所以它當然不起作用 - 你的「捕捉」代碼還沒有被編譯(因爲編譯終止不成功),所以它不能捕捉任何東西。

您需要確保可能有語法錯誤的代碼被編譯比捉碼 - 無論是把它放在你的try子句中導入一個單獨的模塊,或者一個字符串你compile與內置該名稱(如果成功終止,您可以稍後執行由compile調用產生的字節碼)。

我覺得這兩種可能性都不適合你的目的。不幸的是,我懷疑使用兩個單獨的模塊(並且可能根據「這個編譯」檢查選擇它們,但版本檢查聽起來更清晰)是唯一的「乾淨」解決方案。

編輯:這裏是如何微基準嘗試/除了對版本檢查:

$ python2.4 -mtimeit 'try: 
    compile("with x: pass", "", "exec") 
except SyntaxError: x=1 
else: x=2' 
100000 loops, best of 3: 10.8 usec per loop 
$ python2.6 -mtimeit 'try: 
    compile("with x: pass", "", "exec") 
except SyntaxError: x=1 
else: x=2' 
10000 loops, best of 3: 40.5 usec per loop 

$ python2.4 -mtimeit -s'import sys' 'if sys.version>="2.5": x=2 
else: x=1' 
1000000 loops, best of 3: 0.221 usec per loop 
$ python2.6 -mtimeit -s'import sys' 'if sys.version>="2.5": x=2 
else: x=1' 
10000000 loops, best of 3: 0.156 usec per loop 

正如你看到的,我認爲清潔的版本10.8/0.221,快了近50倍,2.4,和40.5/0.156,幾乎在2.6上快260倍。一般情況下(極少數例外),乾淨的(即「pythonic」)方法將成爲Python中更好的優化方法 - 通常,至少部分原因可能是Python核心開發人員專注於促進和鼓勵使用他們喜歡的構造,而不是他們不喜歡的構造。

+0

我很害怕這個。正如你所說,有條件地編譯一個字符串聽起來相當麻煩,沒有很好的理由,所以沒有了。所以我會在模塊之間進行選擇,同時保持它們儘可能小。 至於如何區分,捕獲錯誤和檢查版本大致相同的「乾淨」,所以這是更快 - 每次比較sys.version_info或有時吃異常?這可能可以忽略不計,但我想要一個意見。 感謝您的快速回答! – 2010-08-19 03:56:49

+1

@hippie,以微觀基準的東西,永遠不會猜測,總是_measure_。 'timeit'是你的朋友。編輯我的A來舉例。 – 2010-08-19 05:09:39

+0

當然,版本檢查比編譯更快。要做比較測試的任何事情,它需要導入(編譯)代碼,而不僅僅是做兩個任務。對於Python 2.5,異常檢查實際上稍微快一點(我的機器上的3.47s和3.87s,在timeit中有1,000,000次迭代)。但是,在2.4中,由於每次捕獲SyntaxError,異常檢查的速度會降低大約30倍。版本檢查顯然更好,但你的例子並沒有顯示真正的原因。 =) – 2010-08-19 22:19:51