Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Обработка ошибок в жанре panic/defer на Python

Anna | 16.06.2014 | нет комментариев
Обработка ошибок в Go построена не на закостенелом механизме исключений, а на новом увлекательном механизме отложенных обработчиков. В качестве увлекательного изыскания я реализовал такую обработку ошибок на Python. Кому увлекательно, заходите.


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

func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
        return
    }
    defer src.Close()

    dst, err := os.Create(dstName)
    if err != nil {
        return
    }
    defer dst.Close()

    return io.Copy(dst, src)
}

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

Сходственное поведение дозволено реализовать на Python, вследствие эластичности языка. Для этого объявляются соответствующие функции, которые применяют особые переменные в стеке, Дабы вешать обработчики на функцию, и устанавливать особый ранг в случае поправления. Для указания в функции поддержки данного механизма применяется декоратор, тот, что создаём список для хранения отложенных функций, и перехватывает исключение для их вызова. Код:

# Go-style error handling

import inspect
import sys

def panic(x):
    raise Exception(x)

def defer(x):
    for f in inspect.stack():
        if '__defers__' in f[0].f_locals:
            f[0].f_locals['__defers__'].append(x)
            break

def recover():
    val = None
    for f in inspect.stack():
        loc = f[0].f_locals
        if f[3] == '__exit__' and '__suppress__' in loc:
            val = loc['exc_value']
            loc['__suppress__'].append(True)
            break
    return val

class DefersContainer(object):
    def __init__(self):
        # List for sustain refer in shallow clone
        self.defers = []

    def append(self, defer):
        self.defers.append(defer)

    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_value, traceback):
        __suppress__ = []
        for d in reversed(self.defers):
            try:
                d()
            except:
                __suppress__ = []
                exc_type, exc_value, traceback = sys.exc_info()
        return __suppress__

def defers_collector(func):
    def __wrap__(*args, **kwargs):
        __defers__ = DefersContainer()
        with __defers__:
            func(*args, **kwargs)
    return __wrap__

@defers_collector
def func():
    f = open('file.txt', 'w')
    defer(lambda: f.close())

    defer(lambda : print("Defer called!"))

    def my_defer():
        recover()

    defer(lambda: my_defer())

    print("Ok )")
    panic("WTF?")

    print("Never printed (((")

func()
print("Recovered!")

Я использую lambda для фиксации доводов при отложенном вызове, Дабы повторить поведение оператораdefer.

Функциональную идентичность в нюансах не тестировал. Но если знаете что необходимо доработать, пишите.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB