2010-08-19 3 views
2

Я пытаюсь использовать модуль python-daemon. Он предоставляет класс daemon.DaemonContext для правильного демонстрации сценария. Хотя я в первую очередь нацелен на Python 2.6+, я бы хотел поддерживать обратную совместимость с версией 2.4.Работа с классами контекста в Python 2.4

Python 2.5 поддерживает импорт контекстов с будущим, но Python 2.4 не имеет такого объекта. Я понял, что могу просто уловить любую ошибку, с помощью которой высказывается утверждение, и вводить и выходить из контекста вручную для 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) 

ответ

3

SyntaxError диагностируется компилятором Python, как он компилирует - вы, вероятно, пытаясь «поймать» его из кода, который скомпилированного в рамках одного и того же модуля (например, это то, что вы делаете в ваш образец кода), поэтому, конечно, это не сработает - ваш «ловушка» код еще не скомпилирован (потому что компиляция завершилась неудачно), поэтому он ничего не может поймать.

Вы должны гарантировать, что код, который может иметь синтаксическую ошибку компилируется позже чем улавливающей код - либо поместить его в отдельный модуль, который вы импортируете в пункте try, или в строку, которую вы compile с (впоследствии вы можете выполнить байт-код, вызванный вызовом compile, если он завершается успешно).

Никакая возможность не подходит для ваших целей, я думаю. Я подозреваю, что использование двух отдельных модулей (и, вероятно, выбор между ними в зависимости от проверки «делает ли это компиляция», но проверка версии звучит намного чище для меня) является единственным «чистым» решением, к сожалению.

Edit: вот как 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, почти в 50 раз быстрее, на 2,4 и 40.5/0.156, почти В 260 раз быстрее, на 2.6. В целом (за редким исключением) чистый (т. Е. «Питонический») подход окажется лучше оптимизированным в Python - часто, по крайней мере, часть причины может заключаться в том, что основные разработчики Python сосредоточены на облегчении и поощрении использование конструкций, которые им нравятся, а не конструкции, которые им не нравятся.

+0

Я боялся этого. Как вы сказали, условная компиляция строки звучит довольно беспорядочно, потому что это не так. Поэтому я буду выбирать между модулями, сохраняя их как можно меньше. Что касается того, как различать, ловить ошибку и проверять версию, примерно одинаково «чист», так что быстрее - сравнивая sys.version_info каждый раз или иногда есть исключение? Это, вероятно, незначительно, но мне хотелось бы получить мнение. Спасибо за ваш быстрый ответ! –

+1

@hippie, для микро-тестов, никогда не догадываться, всегда _measure_. 'timeit' - ваш друг. Редактирование моего A для примера. –

+0

Конечно, проверка версии выполняется быстрее, чем компиляция. Чтобы что-либо сделать с помощью теста сравнения, ему нужно будет импортировать (компилировать) код, а не просто выполнять два назначения. Для Python 2.5 проверка исключения на самом деле немного быстрее (3.47s против 3.87s на моей машине с 1,000,000 итерациями через timeit). Однако на 2.4 проверка исключения примерно в 30 раз медленнее из-за того, что каждый раз захватывает SyntaxError. Проверка версии, очевидно, лучше, но ваш пример не показывает реальной причины. знак равно –