Генерация сообщений в Mathematica
В модуле, который я пишу, у меня есть (для фаз разработки и тестирования) много Print["Messages"]
, У меня есть два вопроса:
- Как лучше печатать такие "отладочные" сообщения?
- Можно ли вызвать модуль так, чтобы сообщения НЕ печатались? Например, при вызове модуля из другого модуля я бы не хотел видеть все выходные данные первого.
5 ответов
Мне нравится всегда держать глобальные переменные с префиксом $
и функционирует без префикса, поэтому я бы написал:
debugPrint[args___] := $debugPrintFunction[args]
$debugPrintFunction = Print[##] &
Тогда вы можете просто использовать debugPrint
точно так же, как вы бы использовали Print
сейчас. Когда вы хотите избавиться от отладочных сообщений, вы просто сбрасываете переменную:
$debugPrintFunction = .
Есть некоторые преимущества сделать это таким образом. Во-первых, вы можете использовать Block
чтобы включить или отключить отладку локально:
In[1]:= foo[x_] := (debugPrint[x]; x+1)
In[2]:= foo[3]
3
Out[2]= 4
In[3]:= Block[{$debugPrintFunction}, foo[3]
Out[3]= 4
Вы можете даже на месте сделать $debugPrintFunction
делать что-то еще, например Sow
значения для Reap
забрать или направить сообщения отладки в другое место, например
strm = OpenWrite["your/log/path/here", InputForm];
Block[{$debugPrintFunction = Write[strm, ##]},
foo[3]];
Close[strm];
При разумном использовании динамическое определение объема Block
позволяет использовать глобальные переменные относительно безопасным и контролируемым образом.
Мой старый код использует метод, который описывает Pillsy.
Совсем недавно я использовал голову, которая обычно не имеет никаких правил, например:
...
debugPrint[expr]
...
а затем есть вторая функция:
Attributes[PrintDebug]={HoldAll}
PrintDebug[expr_] := Block[{debugPrint = Print}, expr]
Затем, когда я хочу увидеть результаты отладки, я могу обернуть PrintDebug вокруг ввода:
PrintDebug[MyFunction[1,2,3]]
или чаще
MyFunction[1,2,3] // PrintDebug
поскольку я считаю, что постфиксную форму легче добавлять / удалять и лучше оставить основной упор на основной функции.
Я обычно устанавливаю в своих функциях многословную опцию, которую можно включить / выключить при необходимости для отладки. Обратите внимание, что указав значение по умолчанию для Verbose внутри функции, вы можете контролировать, будет ли информация печататься или нет.
In[5]:= func1[arg_, opts___] := Module[{verbose},
verbose = Verbose /. {opts} /. {Verbose -> True};
If[verbose, Print["Verbosing function1: arg is ", arg]];
arg
];
func2[arg_, opts___] := Module[{verbose},
verbose = Verbose /. {opts} /. {Verbose -> False};
func1[arg, Verbose -> verbose]
];
In[7]:= func1[123]
During evaluation of In[7]:= Verbosing function1: arg is 123
Out[7]= 123
In[8]:= func2[456]
Out[8]= 456
In[9]:= func1[123, Verbose -> False]
Out[9]= 123
In[10]:= func2[456, Verbose -> True]
During evaluation of In[10]:= Verbosing function1: arg is 456
Out[10]= 456
Конечно, можно разработать этот пример, чтобы соответствовать стандартам программирования Mathematica (например, добавив Options[func1, Verbose -> ...]
заголовок, а затем доступ к опциям внутри функции, но здесь дело не в этом.
Еще одна возможность:
debugPrint::msg = "Debug message: `1`";
debugPrint[msg_] := Message[debugPrint::msg, msg]
Используйте функцию как это:
debugPrint["hello"]
Выключите или включите такие сообщения:
Off[debugPrint::msg]
On[debugPrint::msg]
Для меня, поскольку у M нет встроенного отладчика, о котором можно говорить, я трачу 50% своего времени только на отладку, которую можно было бы сэкономить, если бы был отладчик. 50% моего кода разработки составляют операторы Print, так как без них я потеряюсь, обнаружив, откуда исходит ошибка. (это также плохо, так как слишком большое количество печатных сообщений в коде иногда затрудняет просмотр алгоритма, он мешает, но не может удалить его, поскольку он может понадобиться мне позже).
Я нахожу удивительным, что такой мощный и гибкий вычислительный инструмент, как M, все еще имеет относительно менее продвинутую среду разработки. Когда я использую Matlab, у меня уходит несколько секунд, чтобы найти ошибку, используя отладчик.
Кто-то может сказать, использовать Workbench для отладки. Я попытался использовать для отладки демонстрации Manipulate, и я не могу понять это. Слишком сложный в использовании. M нуждается в простой простой в использовании встроенной программе отладчика (в самой записной книжке, а не в отдельной программе) и с номерами строк!
Хорошо, учитывая приведенное выше введение:), это то, что я делаю сам в ответ на ваш вопрос:
имеют разные уровни отладочных сообщений. грубый уровень и уровень детализации. Грубый уровень печатает только сообщение, когда оно входит в функцию и когда она существует в функции.
У меня есть кнопка в пользовательском интерфейсе для включения / выключения отладки (если вы делаете программу, основанную на пользовательском интерфейсе, иначе она будет в коде).
Используйте отдельную функцию отладки, где отладочное сообщение проходит перед печатью. Там вы можете добавить отметку времени к каждому сообщению и тому подобное перед печатью (также можете контролировать, хотите ли вы, чтобы сообщения отправлялись в текстовый файл из одного места). Остальная часть вашего кода, просто вызывает эту функцию отладки с сообщением для печати. Теперь я печатаю все на консоли, а не на текущей записной книжке.
Каждое отладочное сообщение имеет имя функции, которая вызывала его при запуске.
Если вы хотите контролировать отладку на уровне модуля, то, что я делаю, это просто делает локальный флаг отладки внутри модуля и включаю / выключаю его каждый раз, когда я хочу отладить этот конкретный модуль. Этот локальный флаг отладки принимает настройку глобального флага отладки. Таким образом, я могу отлаживать только один модуль, если я хочу, а не остальную часть кода.
Есть много других способов настроить все это. Но я обнаружил, что если я потрачу больше времени на создание хорошей системы отладочных сообщений, это поможет выделить ошибки при необходимости.
Вот несколько полезных ссылок
http://reference.wolfram.com/mathematica/guide/TuningAndDebugging.html
отладчик рабочей среды (если вы можете понять, как использовать для отладки Manipulate и Dynamics, пожалуйста, дайте мне знать)
http://www.wolfram.com/products/workbench/features/debug.html