Pull to refresh
1
0

Пользователь

Send message

Парсить каждый раз не надо. Ведь Вы уже реализовали все что нужно тут: https://github.com/meklon/morphostain/blob/660102bc1b11641e845966754b4dff80cca905fc/morphostain/morphostain.py#L460-L461


Почему var_pause, matrix_stains, path_output, path_output_log, str_ch0, str_ch1, str_ch2, thresh_0 и thresh_1 там передаются, а dpi нет? Ведь все эти значения тоже "константы по сути для каждого запуска".


Если кажется, что список аргументов слишком длинный, но все аргументы действительно нужны, то можно их собрать в словарь, объект или namedtuple, и передавать все (или сколько надо) за раз.

Также обратите внимание, как комментарии превратились в название функций. Если у участка кода комментарий более длинный, его можно положить в докстринг новой функции, то есть получится настоящая документация, которую через Sphinx опубликовать можно, например!


Это все, что я расказываю, важно в долгосрочной перспективе, потому что хороший код поддерживать проще. Если надо что-то сделать быстро на один раз, то можно и не заморачиваться :)

У Вас image_process это как будто main подпроцессов. Не понятно, почему некоторые данные из main родительского процесса передаются в image_process напрямую через аргументы, а некоторые через глобальный args. Более того, некоторые вещи там продублированы. Например, ничто не мешает другому программисту (или даже не другому) случайно использовать args.thesh0 вместо thresh0, что может привести к ошибкам (например когда thresh0 не был указан при вызове и его надо было добыть из json). Такую ошибку сделать сложнее, если есть только один источник входных данных.


В общем, входные параметры не перестают быть входными если их передать в функцию в обход списка ее аргументов. Просто в таком случае за ними следить надо бдительнее. Проще просто не использовать глобальные переменные.

Если функция одна, то код выглядит она примерно так:


def f():
    # do one thing
    x = 87
    y = x * 3

    # do another thing
    z = y / 7
    return z

А если несколько, то так:


def f():
    y = do_one_thing()
    z = do_another_thing(y)
    return z

def do_one_thing():
    x = 87
    return x * 3

def do_another_thing(y):
    z = y / 7
    return z

Ухудшает ли это читаемость, или улучшает — вопрос субъективный. Я лично считаю, что улучшает, особенно читаемость функции f. Так становится проще определить что функция делает, а не как.


Фишка в том, что если задача сама по себе сложная (complex), то код ее решения будет как минимум таким же сложным (complex), иначе он будет запутнным (complicated). Сложный код структурно состоит из менее сложных компонентов, каждый из которых решает подзадачу основной задачи, и их по отдельности можно понять и протестировать. А в запутанном коде компоненты перемешаны и зависимости между ними проследить сложно. А значит понять и внести изменения в запутанный код без непредвиденных последствий трудно.

Обычно если есть такая цепочка, значит функция в середине цепочки (f2) это на самом деле не одна функция, а несколько.


Давайте рассмотрим упрощенный пример:


def process_args(arg1, arg2, arg3):
    """Точка входа в программу.
    arg1 - собственный аргумент. Остальные аргументы передаются дальше.
    """
    print(arg1)
    f2(arg2, arg3)

def f2(arg2, arg3):
    """Зависит только от arg2.
    arg3 тут только, чтобы передать в f3().
    """
    data = arg2
    data[0] = 42
    f3(data, arg3)
    print(data)

def f3(arg2, arg3):
    print(arg2, arg3)

Тут process_args некоторым образом обрабатывает некоторые данные. Обратите внимание, что f3 зависит от промежуточного состояния f2. Казалось бы, деваться некуда, придется либо arg3 делать глобальным, либо тянуть его по цепочке. На самом деле эту проблему можно легко решить, осознав, что f2 на самом деле производит 2 разных действия, и если их на самом деле разбить на 2 отдельные функции, то проблема с цепочкой исчезнет. Вот так:


def process_args(arg1, arg2, arg3):
    """Точка входа в программу.
    arg1 - собственный аргумент. Остальные аргументы передаются дальше.
    """
    print(arg1)
    intermediate_f2_result = f2a(arg2)
    f2b(intermediate_f2_result, arg3)

def f2a(arg2):
    """Зависит только от arg2."""
    data = arg2
    data[0] = 42
    return data

def f2b(arg2_processed, arg3):
    """Зависит и от arg2_processed и от arg3.
    Более того, зависимость от обоих аргументов указана явно!
    """
    f3(arg2_processed, arg3)
    print(arg2_processed)

def f3(arg2, arg3):
    print(arg2, arg3)

Аналогичного результата можно добиться, используя функцию обратного вызова:


def process_args(arg1, arg2, arg3):
    """Точка входа в программу.
    arg1 - собственный аргумент. Остальные аргументы передаются дальше.
    """
    print(arg1)

    def callback(arg2_processed):
        # Ссылку на arg3 эта функция получит из области видимости process_args,
        # так что протаскивать arg3 в f2 не нужно.
        f3(arg2_processed, arg3)

    f2(arg2, callback)  # тут arg3 больше не фигурирует

def f2(arg2, cb):
    """Зависит только от arg2."""
    data = arg2
    data[0] = 42
    cb(data)  # вместо f3; arg3 тут не передаем, но f3 его все равно получит
    print(data)

def f3(arg2, arg3):
    print(arg2, arg3)

У Вас в Morphostain есть эта проблема в group_analyze, например. Если ее раздробить на отдельные функции, то не будет необходимости использовать глобальные args в plot_group. На самом деле определить, нуждается ли функция в разделении можно, подобрав ей правильное название. Я бы group_analyze назвал group_analyze_and_print_and_plot. Видите, уже 3 функции напрашивается.


Если организовать код немного по-другому, необходимость тянуть аргументы из функции в функцию, используя их только на самом низком уровне, отпадает. А если функция действительно использует параметр, то нет причин получать его откуда-то кроме списка аргументов (кроме самого высокого уровня, функции main, где списка аргументов нет, и входные данные надо явно доставать из sys.argv или откуда-то еще). Надеюсь, я понятно объясняю.

Если вам надо таскать из функции в функцию одни и те же переменные, значит у Вас там на самом деле класс, скорее всего.


Кроме того, функции, неявно зависящие от глобального состояния, сложно тестировать.

… а слова в названиях отделяются нижним подчеркиванием

А какие еще бывают подчеркивания?

Граждане US за это деньги платят ведь.

Сократ выражал аналогичные опасения по отношению к распространению письменности: https://youtu.be/XNIHBEBsoKg?t=24


[writing] will introduce forgetfulness into the soul of those who learn it: they will not practice using their memory because they will put their trust in writing, which is external and depends on signs that belong to others, instead of trying to remember from the inside, completely on their own.

Источник


Перевод

[Писменность] принесет забывчивость в серца тех, кто ее изучает; они не будут тренировать память, потому что доверятся внешней, и зависащей от принадлежащих другим знаков, письменности вместо того, чтобы пытаться запомнить все самостоятельно.

jge @ECF81536; делает переход, если a больше или равно b

Разве не когда b больше или равно a? Условие же задом наперед записано, а переменные в комментарии местами поменять забыли (в оригинальной статье тоже).

Разве беспилотники не могут сами прилетать на станции обслуживания?
С каких это пор автопилот — нестандартная область применения машинного обучения?
Это не метафора.

А что же это тогда?

Я уверен, что имелась в виду эта галочка:


Скриншот интерфейса переименования файла в PyCharm

image


Если ее включить, то "нормальная IDE например WebStorm" будет файл искать в строках и комментариях, вне зависимости от того, является ли строка аргументом функции require или нет.

Просто нет простого способа указать компилятору не удалять переменную автоматически когда она выходит из области видимости.

Щас не понятно было. Раз переменная выходит из области видимости, значит код ее напрямую увидеть не сможет, првильно? Тогда почему бы компилятору ее не удалить? Если же какое-то значение нужто сохранить на потом, надо его положить в какую-то структуру с соотвутствующе расставлеными lifetimes. Тогда значение будет доступно ровно столько, сколько надо. Ведь именно для этого и были придуманы lifetimes.

По-вашему, 50% дисков в RAID1 тоже простаивают?

В первом же абзаце написано, что systemd-networkd требует всего 2 МБ памяти (против 20 у NetworkManager).

Может с server push разница не будет так заметна, а в реальных сценариях использования будет выигрыш за счет пропуска неиспользуемых спрайтов (зачем мне 4 набора спрайтов глобуса, если 3 из них я никогда не увижу?) и более оптимальной работы кэша (при редактировании одного спрайта необходимо перезагрузить лишь измененный спрайт вместо всего суперспрайта)?

Это названия деревни в Британии.

Information

Rating
Does not participate
Location
Острог, Ровенская обл., Украина
Date of birth
Registered
Activity