处理Python 2.4中的上下文类

时间:2010-08-19 03:17:47

标签: python backwards-compatibility with-statement

我正在尝试使用python-daemon模块。它提供daemon.DaemonContext类以正确守护脚本。虽然我主要针对Python 2.6+,但我希望保持与2.4版本的向后兼容性。

Python 2.5支持从 future 导入上下文,但Python 2.4没有这样的功能。 我想我可以抓住with语句引发的任何错误,并手动进入和退出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)

1 个答案:

答案 0 :(得分:3)

SyntaxError是由Python编译器诊断为它编译 - 你大概是想“抓”,它从被被编译为同一模块的一部分代码(例如,这就是你在做什么你的代码示例),所以当然它不会工作 - 你的“捕获”代码还没有被编译(因为编译已经终止失败)所以它无法捕获任何东西。

您需要确保可能会出现语法错误的代码稍后而不是捕获代码 - 将其放在您在try子句中导入的单独模块中,或者使用该名称内置的compile字符串(如果成功终止,您可以稍后执行compile调用产生的字节码)。

我认为这两种可能性都不适合您的目的。我怀疑使用两个单独的模块(并且可能根据“执行此编译”检查它们之间进行选择,但对我来说版本检查听起来更干净)是不幸的唯一“干净”解决方案。

编辑:以下是如何对版本检查进行microbenchmark尝试/除外:

$ 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,比2.4快几乎快50倍,40.5 / 0.156快2.6倍。一般来说(除了极少数例外),清洁(即“Python的”)的方法将变成是在Python中更好地优化一个 - 通常,原因至少部分可以是Python的核心开发人员专注于促进和鼓励使用他们喜欢的结构,而不是他们不喜欢的结构。