在 Python 2.4 中处理上下文类
我正在尝试使用 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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
SyntaxError
由 Python 编译器在编译时诊断 - 您可能试图从作为同一模块的一部分编译的代码中“捕获”它(例如,这就是您在你的代码示例),所以当然它不会工作——你的“捕获”代码还没有被编译(因为编译未成功终止)所以它不能捕获任何东西。您需要确保可能存在语法错误的代码晚于捕获代码进行编译 - 或者将其放入在
try
子句中导入的单独模块中,或者在您使用该名称的内置函数进行编译的字符串中(如果成功终止,您可以稍后执行编译调用生成的字节码)。我认为这两种可能性都不适合您的目的。不幸的是,我怀疑使用两个单独的模块(并且可能根据“是否编译”检查在它们之间进行选择,但版本检查对我来说听起来更干净)是唯一的“干净”解决方案。
编辑:以下是如何针对版本检查对 try/ except 进行微基准测试:
如您所见,我认为更干净的版本是
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 youcompile
with the built-in by that name (you can later execute the bytecode resulting from thecompile
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:
As you see, the version I consider cleaner is
10.8 / 0.221
, almost 50 times faster, on 2.4, and40.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.