Python, эквивалентный из '#define func () 'или как прокомментировать вызов функции в Python

мой код Python чередуется с большим количеством вызовов функции, используемых для (debugging|profiling|tracing и т.д.), например:

import logging

logging.root.setLevel(logging.DEBUG)
logging.debug('hello')
j = 0
for i in range(10):
    j += i
    logging.debug('i %d j %d' % (i,j))
print(j)
logging.debug('bye')

я хочу к #define эти функции потребления ресурса из кода. что-то как c эквивалент

#define logging.debug(val)

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

одна идея состоит в том, чтобы переопределить функции, которые я хочу прокомментировать в пустые функции:

def lazy(*args): pass
logging.debug = lazy

вышеупомянутая идея все еще вызывает функцию и может создать несметное число других проблем

9
задан Artjom B. 3 April 2015 в 14:53
поделиться

9 ответов

На Python нет препроцессора, хотя вы можете запустить исходный код питона через внешний препроцессор, чтобы получить тот же эффект - например, sed "/logging.debug/d" удалит все команды протоколирования отладки. Однако это не очень элегантно - в конечном итоге вам понадобится какая-нибудь сборочная система, чтобы запустить все ваши модули через препроцессор и, возможно, создать новое дерево каталогов обрабатываемых .py файлов перед запуском основного скрипта.

Или же, если вы поместите все отладочные утверждения в блок , если __debug__:, то они будут оптимизированы при запуске питона с флагом -O (optimise).

В качестве альтернативы, я проверил код с дис-модулем, чтобы убедиться, что он действительно оптимизирован. Я обнаружил, что и

if __debug__: doStuff()

и

if 0: doStuff()

оптимизированы, но

if False: doStuff()

- нет. Это связано с тем, что False является обычным Python-объектом, и на самом деле это можно сделать:

>>> False = True
>>> if False: print "Illogical, captain"
Illogical, captain

Что кажется мне дефектом в языке - надеюсь, это исправлено на Python 3.

Edit:

Это исправлено на Python 3: Assigning to True or False Теперь выдаётся SyntaxError. Поскольку на Python 3 True и False являются константами, это означает, что если False: doStuff() теперь оптимизировано:

>>> def f():
...     if False: print( "illogical")
... 
>>> dis.dis(f)
  2           0 LOAD_CONST               0 (None) 
              3 RETURN_VALUE         
17
ответ дан 4 December 2019 в 11:05
поделиться

Ну, ты всегда можешь реализовать свой собственный простой препроцессор, который делает трюк. Или, что еще лучше, вы можете использовать уже существующий. Скажем http://code.google.com/p/preprocess/

1
ответ дан 4 December 2019 в 11:05
поделиться

Прежде чем вы это сделаете, вы составили профиль, чтобы убедиться, что на самом деле лесозаготовка занимает значительное количество времени? Вы можете обнаружить, что вы тратите больше времени, пытаясь удалить звонки, чем сэкономили.

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

Если вы все еще находите, что протоколирование занимает значительное количество времени, то вы можете посмотреть на переопределение функции протоколирования внутри критических циклов, возможно, путем привязки локальной переменной к функции протоколирования или к фиктивной функции (или проверкой None перед ее вызовом).

.
0
ответ дан 4 December 2019 в 11:05
поделиться

определить функцию, которая ничего не делает, т.е.

def nuzzing(*args, **kwargs): pass

Затем просто перегрузите все функции, от которых вы хотите избавиться со своей функцией, ala

logging.debug = nuzzing
0
ответ дан 4 December 2019 в 11:05
поделиться

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

Но самый чистый подход - игнорировать низкоприоритетные лог-сообщения (как вы и предлагали):

logging.root.setLevel(logging.CRITICAL)
-1
ответ дан 4 December 2019 в 11:05
поделиться
[

] Хотя я думаю, что вопрос совершенно ясен и обоснован (несмотря на многочисленные ответы, которые предполагают обратное), короткий ответ - "на Питоне это не поддерживается"[

]. [

] Единственным потенциальным решением, кроме предложения [] препроцессора [], было бы использование некоторого [] байткодного взлома []. Я даже не начну представлять, как это должно работать с точки зрения высокоуровневого API, но на низком уровне можно было бы представить себе просмотр объектов кода на предмет определенных последовательностей инструкций и их переписывание для устранения. [

] [

] Например, посмотрите на следующие две функции: [

]. [
>>> def func():
...    if debug:  # analogous to if __debug__:
...       foo
>>> dis.dis(func)
  2           0 LOAD_GLOBAL              0 (debug)
              3 JUMP_IF_FALSE            8 (to 14)
              6 POP_TOP

  3           7 LOAD_GLOBAL              1 (foo)
             10 POP_TOP
             11 JUMP_FORWARD             1 (to 15)
        >>   14 POP_TOP
        >>   15 LOAD_CONST               0 (None)
             18 RETURN_VALUE
] [

] Здесь можно сканировать на []LOAD_GLOBAL[] из [] debug[] и устранить его и все до []JUMP_IF_FALSE[] цели.[

]. [

] Это более традиционная функция debug() в стиле Си, которая красиво стирается препроцессором:[

]. [
>>> def func2():
...    debug('bar', baz)
>>> dis.dis(func2)
  2           0 LOAD_GLOBAL              0 (debug)
              3 LOAD_CONST               1 ('bar')
              6 LOAD_GLOBAL              1 (baz)
              9 CALL_FUNCTION            2
             12 POP_TOP
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE
] [

] Здесь вы бы искали []LOAD_GLOBAL[] из [] debug[] и протирали бы все до соответствующего []CALL_FUNCTION[].[

]. [

] Конечно, оба эти описания того, что вы бы сделали, гораздо проще, чем то, что вам действительно нужно для всех, кроме самых простых моделей использования, но я думаю, что это было бы осуществимо. Сделал бы симпатичный проект, если бы никто этого еще не делал. [

]
2
ответ дан 4 December 2019 в 11:05
поделиться
[

] Я думаю, что полностью отказаться от вызова функции нецелесообразно, так как Python работает по-другому, чем C. #define происходит в пре-компиляторе, перед компиляцией кода. На Python такого нет.[

] [

]Если вы хотите полностью удалить вызов для отладки в рабочей среде, я думаю, единственный способ, если действительно изменить код перед выполнением. С помощью скрипта перед выполнением вы можете комментировать/разделывать отладочные строки. [

] [

] Что-то вроде этого: [

] [

]Файл logging.py[

] [
#Main module
def log():
    print 'logging'

def main():
    log()
    print 'Hello'
    log()
] [

]Файл call_log.py[

] [
import re
#To log or not to log, that's the question
log = True

#Change the loging
with open('logging.py') as f:
    new_data = []
    for line in f:
       if not log and re.match(r'\s*log.*', line):
         #Comment
         line = '#' + line
       if log and re.match(r'#\s*log.*', line):
         #Uncomment
         line = line[1:]
       new_data.append(line)

#Save file with adequate log level
with open('logging.py', 'w') as f:
   f.write(''.join(new_data))


#Call the module
import logging
logging.main()
] [

]Конечно, у него есть свои проблемы, особенно если модулей много и они сложны, но могут быть полезны, если вам нужно полностью избежать вызова функции.[

].
0
ответ дан 4 December 2019 в 11:05
поделиться

Используйте изменяемую переменную модуль?

из Import Debug_flag

из import debug_flag

и используйте эту «переменную» для доступа Gate к функциям регистрации. Вы построили себя модуль модуль , который использует Debug_flag , чтобы ворота функционал регистрации.

0
ответ дан 4 December 2019 в 11:05
поделиться

Мне нравится решение if __debug_, за исключением того, что помещать его перед каждым вызовом немного отвлекает и некрасиво. У меня была такая же проблема, и я решил ее, написав скрипт, который автоматически анализирует ваши исходные файлы и заменяет операторы журналирования операторами pass (и закомментировал копии операторов журналирования). Он также может отменить это преобразование.

Я использую его, когда развертываю новый код в производственной среде, когда есть много операторов регистрации, которые мне не нужны в производственной среде, и они влияют на производительность.

Вы можете найти сценарий здесь: http://dound.com/2010/02/python-logging-performance/

0
ответ дан 4 December 2019 в 11:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: