在 Python 2.4 中处理上下文类

发布于 2024-09-14 15:48:25 字数 1439 浏览 1 评论 0原文

我正在尝试使用 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)

I'm trying to use the python-daemon module. It supplies the daemon.DaemonContext class to properly daemonize a script. Although I'm primarily targeting Python 2.6+, I'd like to maintain backwards compatibility to version 2.4.

Python 2.5 supports importing contexts from future, but Python 2.4 has no such facility.
I figured I could just catch whatever error the with statement raises and enter and exit the context manually for 2.4, but I can't seem to catch the SyntaxError raised.

Is there any way to accomplish this short of explicitly checking the interpreter version?
Below is the gist of what I'm trying to do and the problem I'm getting. In Real Life I don't have control of the context class, so it needs to work without mangling the original class, ie not like these ideas.

Nevermind if Python 2.4 can't run python-daemon; I'd at least like to able to catch the error and implement a fallback or something.

Thanks for helping.

#!/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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

羁〃客ぐ 2024-09-21 15:48:25

SyntaxError 由 Python 编译器在编译时诊断 - 您可能试图从作为同一模块的一部分编译的代码中“捕获”它(例如,这就是您在你的代码示例),所以当然它不会工作——你的“捕获”代码还没有被编译(因为编译未成功终止)所以它不能捕获任何东西。

您需要确保可能存在语法错误的代码晚于捕获代码进行编译 - 或者将其放入在 try 子句中导入的单独模块中,或者在您使用该名称的内置函数进行编译的字符串中(如果成功终止,您可以稍后执行编译调用生成的字节码)。

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

编辑:以下是如何针对版本检查对 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 核心开发人员专注于促进和鼓励使用他们喜欢的结构,而不是他们不喜欢的结构。

SyntaxError is diagnosed by the Python compiler as it compiles -- you're presumably trying to "catch" it from code that's being compiled as part of the same module (e.g., that's what you're doing in your code sample), so of course it won't work -- your "catching" code hasn't been compiled yet (because compilation has terminated unsuccessfully) so it can't catch anything.

You need to ensure the code that might have a syntax error gets compiled later than the catching code -- either put it in a separate module that you import in the try clause, or in a string you compile with the built-in by that name (you can later execute the bytecode resulting from the compile call, if it terminates successfully).

Neither possibility looks good for your purposes, I think. I suspect that using two separate modules (and probably picking between them depending on the "does this compile" check, but a version check sounds much cleaner to me) is the only "clean" solution, unfortunately.

Edit: here's how to microbenchmark try/except against version checks:

$ 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

As you see, the version I consider cleaner is 10.8 / 0.221, almost 50 times faster, on 2.4, and 40.5 / 0.156, almost 260 times faster, on 2.6. In general (with rare exceptions), the clean (i.e., "pythonic") approach will turn out to be the better optimized one in Python -- often, at least part of the reason can be that Python core developers focus on facilitating and encouraging the use of constructs they like, rather than that of constructs they dislike.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文