在Python 2.4中处理上下文类

2 投票
1 回答
1057 浏览
提问于 2025-04-16 03:00

我正在尝试使用python-daemon这个模块。它提供了一个叫daemon.DaemonContext的类,可以正确地将脚本转变为守护进程。虽然我主要是针对Python 2.6及以上版本,但我也想保持对2.4版本的兼容性。

Python 2.5支持从future模块导入上下文,但Python 2.4没有这样的功能。我想我可以捕捉到with语句引发的任何错误,然后手动进入和退出上下文,但我似乎无法捕捉到引发的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)

1 个回答

3

SyntaxError 是 Python 编译器在编译代码时发现的错误。你可能在尝试从同一个模块中捕捉这个错误(比如你在代码示例中做的那样),但这当然是行不通的,因为你的“捕捉”代码还没有被编译(因为编译已经失败了),所以它无法捕捉到任何东西。

你需要确保可能出现语法错误的代码在“捕捉”代码之后被编译。你可以把它放在一个单独的模块中,然后在 try 语句中导入这个模块,或者把这段代码放在一个字符串里,用 Python 内置的 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 倍。一般来说(虽然有少数例外),干净的(也就是“符合 Python 风格的”)方法在 Python 中通常会被优化得更好——通常,部分原因是 Python 的核心开发者更倾向于支持和鼓励使用他们喜欢的结构,而不是那些他们不喜欢的结构。

撰写回答