Как бы вы сделали эквивалент директив препроцессора в Python?


есть ли способ сделать следующие директивы препроцессора в языке Python?

#if DEBUG

< do some code >

#else

< do some other code >

#endif
6 51

6 ответов:

здесь __debug__, что является специальным значением, которое компилятор выполняет предварительную обработку.

if __debug__:
  print "If this prints, you're not running python -O."
else:
  print "If this prints, you are running python -O!"

__debug__ будет заменен на константу 0 или 1 компилятором, и оптимизатор удалит любой if 0: строки перед интерпретацией источника.

Я написал препроцессор python под названием pypreprocessor, который делает именно то, что вы описываете.

источник и документация доступны на Google Code.

пакет также может быть загружен / установлен через PYPI.

вот пример, чтобы выполнить то, что вы описываете.

from pypreprocessor import pypreprocessor

pypreprocessor.parse()

#define debug

#ifdef debug
print('The source is in debug mode')
#else
print('The source is not in debug mode')
#endif

pypreprocessor способен на гораздо больше, чем просто на лету предварительной обработки. Чтобы увидеть больше примеров проверить проект на GitHub.

обновление: дополнительная информация о pypreprocessor

способ выполнения предварительной обработки прост. В приведенном выше примере препроцессор импортирует объект pypreprocessor, созданный в модуле pypreprocessor. Когда вы вызываете parse() на препроцессоре, он сам потребляет файл, в который он импортируется, и генерирует временную копию самого себя, которая комментирует весь код препроцессора (чтобы избежать препроцессора от вызова себя рекурсивно в бесконечном цикле) и комментирует все неиспользуемые части.

комментирование строк, в отличие от их удаления, необходимо для сохранения номеров строк при трассировке ошибок, если модуль создает исключение или аварийно завершает работу. И я даже зашел так далеко, чтобы переписать трассировку ошибок, чтобы отчет отражал правильное имя файла модуля, который разбился.

затем выполняется сгенерированный файл, содержащий постобработанный код на ходу.

преимущество использования этого метода над простым добавлением группы операторов if, встроенных в код, не будет потрачено впустую время выполнения, оценивая бесполезные операторы, потому что закомментированные части кода будут исключены из скомпилированного .файлы pyc.

недостатком (и моя первоначальная причина для создания модуля) является то, что вы не можете запускать python 2x и python 3x в одном файле, потому что интерпретатор pythons выполняет полную проверку синтаксиса до выполнение кода и отклонит любой код конкретной версии до того, как препроцессору будет разрешено запускать :: sigh::. Моя первоначальная цель состояла в том, чтобы иметь возможность разрабатывать код 2x и 3x бок о бок в одном файле, который будет создавать байт-код конкретной версии в зависимости от того, на чем он работает.

в любом случае, модуль препроцессора по-прежнему очень полезен для реализации общих возможностей предварительной обработки в стиле c. Кроме того, препроцессор способен выводить постобработанный код в a файл для последующего использования, если вы хотите.

кроме того, если вы хотите создать версию, которая содержит все директивы препроцессора, а также любые исключенные #ifdefs, это так же просто, как установить флаг в коде препроцессора перед вызовом parse(). Это делает удаление нежелательного кода из исходного файла конкретной версии одноэтапным процессом (против обхода кода и удаления инструкций if вручную).

Я подозреваю, что вы будете ненавидеть этот ответ. То, как вы это делаете в Python-это

# code here
if DEBUG:
   #debugging code goes here
else:
   # other code here.

поскольку python является интерпретатором, нет никакого шага предварительной обработки, который будет применяться, и нет особого преимущества в наличии специального синтаксиса.

вы можете использовать препроцессор в Python. Просто запустите свои скрипты через cpp (C-препроцессор) в вашем каталоге bin. Однако я сделал это с Lua, и преимущества легкой интерпретации перевесили более сложную компиляцию IMHO.

вы можете просто использовать обычные языковые конструкции:

DEBUG = True
if DEBUG:
  # Define a function, a class or do some crazy stuff
  def f():
    return 23
else:
  def f():
    return 42

альтернативный метод заключается в использовании сценария bash для комментирования частей кода, которые имеют отношение только к отладке. Ниже приведен пример скрипта, который комментирует строки, в которых есть оператор "# DEBUG". Он также может удалить эти маркеры комментариев снова.

if [ "" == "off" ]; then
  sed -e '/^#/! {/#DEBUG/ s/^/#/}' -i *.py
  echo "Debug mode to "
elif [ "" == "on" ]; then
  sed -e '/#DEBUG/ s/^#//' -i *.py
  echo "Debug mode to "
else
  echo "usage:  on | off"
fi