2010-08-19 53 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