Питонический способ рефакторинга длиннее «одной строки» if-условие-присваивания (троичный If) - PullRequest
0 голосов
/ 01 марта 2019

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

Поскольку я еще не в питоническом кодированииЯ был бы рад увидеть некоторые предложения по рефакторингу.

for label in range(num_labels):
    d_tresh = drop_treshold[label] if type(drop_treshold) == numpy.ndarray) else drop_treshold     
    r_tresh1 = relabel_treshold1[label] if type(relabel_treshold1) == numpy.ndarray else relabel_treshold1
    r_tresh2 = relabel_treshold2[label] if type(relabel_treshold2) == numpy.ndarray else relabel_treshold2

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

for label in range(num_labels):
    if type(drop_treshold) == numpy.ndarray):
        d_tresh = drop_treshold[label]
    else:
        d_tresh = drop_treshold     

    if type(relabel_treshold1) == numpy.ndarray:
        r_tresh1 = relabel_treshold1[label] 
    else:
        d_tresh = relabel_treshold1

    if type(relabel_treshold2) == numpy.ndarray:
        r_tresh2 = relabel_treshold2[label] 
    else:
        d_tresh = relabel_treshold2

(Конечно, я (sh /) мог бы также выполнить рефакторинг всего кода вокруг показанного примера ... Этот пример фрагмента взят из функции с аргументами, которая могла быбыть скалярным float / int или 1D numpy.array. Если это массив, он будет применять каждый элемент к каждой метке, просто будучи простым скаляром, он будет применять его глобально ко всем меткам) Но здесь снова как pythonic way ?Когда начинать рефакторинг более исчерпывающе, а когда оставаться на месте - потому что это работает?

1 Ответ

0 голосов
/ 01 марта 2019

Проблема в том, что вы повторяете себя для каждой переменной;индексация, если объект является массивом, в противном случае используется объект напрямую.Я бы использовал здесь служебную функцию:

def threshold_label(ob, i):
    # the threshold label can be a scalar or an array
    return ob[i] if isinstance(ob, numpy.ndarray) else ob

for label in range(num_labels):
    d_tresh = threshold(drop_treshold, label)
    r_tresh1 = threshold(relabel_treshold1, label)
    r_tresh2 = threshold(relabel_threshold2, label)

Обратите внимание, что я использовал isinstance() для проверки типа каждого объекта, см. В чем различия между типом() и isinstance ()?

Другой вариант - не проверять массивы каждую итерацию .Проверьте один раз, и, если это не массив, превратите скалярное значение с плавающей запятой или значение int в последовательность ожидаемой длины:

# turn scalar labels into sequences for easy iteration
if not isinstance(drop_threshold, numpy.ndarray):
    drop_threshold = [drop_threshold] * num_labels
if not isinstance(relabel_treshold1, numpy.ndarray):
    relabel_treshold1 = [relabel_treshold1] * num_labels
if not isinstance(drop_threshold, numpy.ndarray):
    relabel_treshold2 = [relabel_treshold2] * num_labels

или, опять же, с помощью вспомогательной функции:

def ensure_sequence(ob, cnt):
    # turn a scalar label value into a sequence if needed
    return [ob] * cnt if not isinstance(ob, numpy.ndarray) else ob

drop_threshold = ensure_sequence(drop_threshold, num_labels)
relabel_treshold1 = ensure_sequence(relabel_treshold1, num_labels)
relabel_treshold2 = ensure_sequence(relabel_treshold2, num_labels)

В этот момент вы можете использовать zip() для итерации:

labels = zip(drop_threshold, relabel_threshold1, relabel_threshold2)
for d_thresh, r_thresh1, r_thresh2 in labels:
    # ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...