Обработка исключений / ошибок в q kdb - альтернатива Try-Catch-finally (Java) / Try-Except-finally (Python) - PullRequest
1 голос
/ 18 июня 2019

Поскольку у нас есть try-catch в java, я могу найти trap-at в q kdb.
Но мое требование - try-catch-finally, т.е. в блоке try я открываю соединение odbc и, наконец, хочузакрыть odbc соединение.

Sudo code:

try{
  con=openODBCConnection(dbName);
  //n statements;
}catch(Exception e){
   catchingNotSoImpException(e)
}finally{
 closeODBCCon(con);
}

Ответы [ 2 ]

5 голосов
/ 18 июня 2019

Это довольно общий подход к использованию логики try-catch-finally в kdb, которая отделяет try-catch, всегда запускает функцию "finally". Это возвращает выходные данные в случае успеха в попытке или в перехвате, если необходимо, или в коде ошибки, если оба попытки и перехвата были прерваны, что позволяет (потенциально) провести более полезное исследование и / или обеспечить безопасность на перерывах:

tcf:{[t;c;f] 
    r:@[(1b;)value@;t;@[(1b;)c@;;(0b;)::]];
    f[]; 
    $[r 0;r 1;'`$r 1]}

Верхняя строка - это часть try-catch.

@[(1b;)value@;t;@[(1b;)c@;;(0b;)::]]

Функция вызывается так:

tcf[(tryfunc;1;`a);catchfunc;finallyfunc]

поэтому входные данные должны быть чем-то, что может быть value 'd в kdb - символе, списке функций и аргументов или строке.

Это можно использовать как есть, но для объяснения:

Ключевая часть логики здесь - это проекции (1b;) и (0b;) вместе с @ в функциях value или c, которые сообщают, что операция ожидает ввода - поэтому в первой части:

(1b;)value@

ожидает ввода t - если операция значения завершается успешно, возвращается (1b;correctOutput), т.е. выполняется проекция.

Если это не удается, ошибка передается на

@[(1b;)c@;;(0b;)::]

По сути, это то же самое, но вместо value используется функция catch c. Это проекция, которая принимает входные данные, переданные из ошибочного значения, а затем применяет те же операции, что и выше. Неудачный вывод передается в глобальный нуль ::.

Это гарантирует, что структура данных r будет иметь начальный 1b, если попытка или перехват был успешным, и 0b, если оба не удаются.

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

Примеры использования определений, подобных ответу Рахула:

q)tryfunc
{x+y}
q)workingcatchfunc
{show "catch";100}
q)brokencatchfunc
{show "catch";1+`a}
q)finallyfunc
{show"finally"}
q)tcf[(tryfunc;1;1);workingcatchfunc;finallyfunc]
"finally"
2
q)tcf[(tryfunc;1;`a);workingcatchfunc;finallyfunc]
"catch"
"finally"
100
q)tcf[(tryfunc;1;`a);brokencatchfunc;finallyfunc]
"catch"
"finally"
'type

Это работает с функциями, принимающими любое количество аргументов:

q)tcf[(monot;1);brokencatchfunc;finallyfunc]
"finally"
10
q)tcf[(monot;`);brokencatchfunc;finallyfunc]
"catch"
"finally"
'type
1 голос
/ 18 июня 2019

В KDB нет блока finally. Один из способов приблизить функциональность к этому в KDB - написать функцию для блока final и вызвать ее как в try, так и в catch. Это не гарантирует, что эта функция будет выполняться всегда, но будет охватывать большинство случаев.

q)finally:{show "finally"}
q)try:{show "try"; show x+y;finally[]}
q)catch:{show "catch"; finally[]}
q).[try;1 2;catch]
Output:
"try"
3
"finally"

Теперь важно, чтобы вы вызывали функцию finally внутри try и catch. Порядок вызова может изменить поведение. Я предлагаю вызвать его в последний раз и всегда возвращать результат из функции finally. Если есть какое-либо возвращаемое значение из try or catch функций, то передайте это значение функции finally. Это уменьшит вероятность ошибок, упростит код, а также устранит другие издержки, такие как проблема порядка вызовов.

Пример возвращаемого значения из блока try:

q) finally:{show "finally"; :x}
q) try:{show "try";r:x+y;finally r}
q) catch:{show "catch"; finally[]}
q) .[tyr;1 2;catch]
Output
"try"
"finally"
3
...