2

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

Python 2.5 支持从future导入上下文,但 Python 2.4 没有这样的功能。我想我可以捕获 with 语句引发的任何错误并手动进入和退出 2.4 的上下文,但我似乎无法捕获引发的 SyntaxError。

除了显式检查解释器版本之外,有什么方法可以实现这一点吗?以下是我正在尝试做的事情的要点以及我遇到的问题。在现实生活中,我无法控制上下文类,因此它需要在不破坏原始类的情况下工作,即不喜欢这些想法。

没关系,如果 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)
4

1 回答 1

3

SyntaxError在编译时由 Python 编译器诊断——您可能正试图从作为同一模块的一部分编译的代码中“捕获”它(例如,这就是您在代码示例中所做的),所以当然它不起作用——你的“捕捉”代码还没有被编译(因为编译没有成功终止)所以它什么也抓不到。

您需要确保可能有语法错误的代码在捕获代码之后try被编译——或者将它放在您在子句中导入的单独模块中,或者放在您compile使用该名称内置的字符串中(您compile如果调用成功终止,则可以稍后执行调用产生的字节码)。

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

编辑:这是针对版本检查对 try/except 进行微基准测试的方法:

$ 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 上快了近 260 倍。一般来说(除了极少数例外),干净(即“pythonic”)方法将成为 Python 中更好优化的方法——通常,至少部分原因可能是 Python 核心开发人员专注于促进和鼓励使用他们喜欢的结构,而不是他们不喜欢的结构。

于 2010-08-19T03:29:00.413 回答