Очистка вложенных Try / Excepts - PullRequest
4 голосов
/ 13 июля 2009

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

for app in apps:
    if app.split('.', 1)[0] == 'zc': #only look for cron in zc apps
        try:
            a = app + '.cron'
            __import__(a)
            m = sys.modules[a]

            try:
                min = m.cron_minute()
                for job in min:
                    k.add_interval_task(job[0], 'minute task', r(M_LB, M_UB),
                                        60*job[1], 
                                        kronos.method.threaded, (), ())
            except AttributeError: #no minute tasks
                pass

            try:
                hour = m.cron_hour()
                for job in hour:
                    k.add_daytime_task(job[0], 'day task', range(1, 8), None,
                                       (job[1], r(H_LB, H_UB)), 
                                       kronos.method.threaded, (), ())
            except AttributeError: #no hour tasks
                pass

        except ImportError: #no cron jobs for this module
            pass

Edit: Объединяя предложения, приведенные ниже, вот моя переписанная форма.

for app in apps:
    if app.split('.', 1)[0] != 'zc': #only look for cron in zc apps
        continue

    try:
        a = app + '.cron'
        __import__(a)
    except ImportError: #no cron jobs for this module, continue to next one
        continue

    m = sys.modules[a]
    if hasattr(m, 'cron_minute'):
        min = m.cron_minute()
        for job in min:
            k.add_interval_task(job[0], 'minute task', r(M_LB, M_UB),
                                60*job[1], 
                                kronos.method.threaded, (), ())

    if hasattr(m, 'cron_hour'):
        hour = m.cron_hour()
        for job in hour:
            k.add_daytime_task(job[0], 'day task', range(1, 8), None,
                               (job[1], r(H_LB, H_UB)), 
                               kronos.method.threaded, (), ())

Ответы [ 4 ]

8 голосов
/ 13 июля 2009

Основная проблема в том, что ваши предложения try слишком широки, особенно самые внешние: с такой привычкой вы БУДЕТЕ рано или поздно столкнетесь с загадочной ошибкой, потому что одна из ваших попыток / исключением случайно скрыла неожиданное исключение " пузырится "от какой-то другой функции, которую вы вызываете.

Поэтому я бы предложил вместо:

for app in apps:
    if app.split('.', 1)[0] != 'zc': #only look for cron in zc apps
        continue

    try:
        a = app + '.cron'
        __import__(a)
    except ImportError: #no cron jobs for this module
        continue

    # etc etc

Кроме того, я также применяю «квартира лучше вложенной» другим способом (не зависящим от какой-либо попытки / кроме), а именно: «если мне больше нечего делать на этом участке цикла, продолжайте [ т. е. перейти к следующему этапу цикла] вместо «если у меня есть что-то делать:», за которым следует значительное количество вложенного кода. Я всегда предпочитал этот стиль (если if / continue или if / return) вложенному if в языках, предоставляющих такую ​​функциональность, как continue (по существу, во всех современных, поскольку в C она есть; -).

Но это простое предпочтение стиля "плоский против вложенного", и суть проблемы заключается в следующем: оставляйте свои предложения try маленькими ! В худшем случае, когда вы просто не можете просто продолжить или вернуться в предложении "исключение", вы можете использовать команду "попробовать / исключить / еще: вставлять в предложение" только то, что абсолютно ДОЛЖНО быть - крошечный фрагмент кода, который, вероятно, и ожидается поднять - и поместить оставшуюся часть следующего кода (часть, которую НЕ предполагается и не ожидается) в предложении else. Это не меняет вложенность, но делает огромную разницу в снижении риска случайного сокрытия исключений, которые НЕ ожидаются!

1 голос
/ 13 июля 2009

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

Другой вариант, который может помочь, - это обернуть только нарушающий код в try-catch, поместив обработчик исключения как можно ближе к исключению. Вот удар:

for app in apps:
    if app.split('.', 1)[0] == 'zc': #only look for cron in zc apps
        try:
            a = app + '.cron'
            __import__(a)
            m = sys.modules[a]
        except ImportError: #no cron jobs for this module
                            #exception is silently ignored
                            #since no jobs is not an error
            continue
        if hasattr(m, "cron_minute"):
            min = m.cron_minute()
            for job in min:
                k.add_interval_task(job[0], 'minute task', r(M_LB, M_UB),
                                    60*job[1], 
                                    kronos.method.threaded, (), ())

        if hasattr(m, "cron_hour"):
            hour = m.cron_hour()
            for job in hour:
                k.add_daytime_task(job[0], 'day task', range(1, 8), None,
                                   (job[1], r(H_LB, H_UB)), 
                                   kronos.method.threaded, (), ())

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

0 голосов
/ 13 июля 2009

Ну, уловка в том, чтобы выяснить, не сломаны ли они. Это обработка часть исключение обработка . Я имею в виду, по крайней мере, напечатать предупреждение, в котором говорится о предположении комментария. Беспокойство о чрезмерной вложенности до того, как фактическая обработка кажется, что вы забегаете вперед. Беспокойство о том, чтобы быть правым, прежде чем быть стильным.

0 голосов
/ 13 июля 2009

Вы можете создать функцию, которая выполняет основную логику, и другую функцию, которая вызывает эту функцию, оборачивая ее операторами try ... кроме. Затем в основном приложении вы можете просто вызвать те функции, которые уже обрабатывают исключения. (По рекомендациям книги «Чистый код»).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...