Форматирование длинных строк Python

Какой был бы красивый способ сделать отступ/форматировать строку в функции ниже? Или я вообще не должен пытаться писать это одним лайнером?

def rects_bound(rects):
    """ Returns a rectangle that bounds all given rectangles
    """
    return reduce(lambda (ax,ay,aw,ah), (bx,by,bw,bh): (min(ax,bx),
                                                        min(ay,by),
                                                        max(ax+aw, bx+bw), 
                                                        max(ay+ah, by+bh)), rects)

или, может быть

def rects_bound(rects):
    """ Returns a rectangle that bounds all given rectangles
    """
    return reduce(lambda (ax,ay,aw,ah), 
                         (bx,by,bw,bh): (min(ax,bx), min(ay,by),
                                         max(ax+aw, bx+bw), max(ay+ah, by+bh)), 
                  rects)

Обычно я просто «подхожу к делу творчески» в таких ситуациях, и я знаю, что, вероятно, нет «правильного» пути, мне просто интересно ваше мнение и привычки.


person noio    schedule 06.01.2012    source источник
comment
-1 Ваша лямбда-функция неверна (см. мой ответ) ... это превосходит любые опасения по поводу длины строки и т. д.   -  person John Machin    schedule 07.01.2012
comment
Прошу прощения? Мой вопрос заключался не в том, делает ли функция то, что она говорит, хотя вы правы в том, что это «неправильно». Мой вопрос был о том, как отформатировать это красиво.   -  person noio    schedule 07.01.2012
comment
Вы спросили мнения. У тебя есть один. Исправьте структуру данных, если можете. Напишите правильную функцию-редуктор. Тогда побеспокойтесь о длине строки.   -  person John Machin    schedule 07.01.2012


Ответы (5)


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

def rects_bound(rects):
    """ Returns a rectangle that bounds all given rectangles
    """
    def bounding_rect_reducer((ax, ay, aw, ah), (bx, by, bw, bh)):
        return (min(ax,bx),
                min(ay,by),
                max(ax+aw, bx+bw), 
                max(ay+ah, by+bh))

    return reduce(bounding_rect_reducer, rects)
person Petr Viktorin    schedule 06.01.2012

Во-первых, по возможности избегайте длинных очередей. Этот конкретный пример можно было бы написать гораздо более читабельно, как

def rects_bound(rects):
    x0 = min(x for x, y, w, h in rects)
    y0 = min(y for x, y, w, h in rects)
    x1 = max(x + w for x, y, w, h in rects)
    y1 = max(y + h for x, y, w, h in rects)
    return x0, y0, x1, y1

Если вы предпочитаете избегать переменных, вы также можете использовать

def rects_bound(rects):
    return (min(x for x, y, w, h in rects),
            min(y for x, y, w, h in rects),
            max(x + w for x, y, w, h in rects),
            max(y + h for x, y, w, h in rects))

который я все еще нахожу гораздо более читаемым, чем ваш исходный код.

(Обратите внимание, что я предполагаю, что rects допускает несколько итераций.)

person Sven Marnach    schedule 06.01.2012
comment
@Noio: В чем проблема с четырьмя итерациями? (Что бы это ни стоило, моя версия в два раза быстрее вашей на моей машине.) - person Sven Marnach; 07.01.2012
comment
@SvenMarnach Одна проблема заключается в том, что в вашей версии больше нельзя передавать генератор в качестве аргумента rects. - person Bolo; 01.08.2012
comment
@Bolo: Да, это то, что означает комментарий в конце этого ответа. - person Sven Marnach; 01.08.2012

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

Глядя на ваши 2 примера, я бы выбрал второй или этот:

def rects_bound(rects):
    """ Returns a rectangle that bounds all given rectangles
    """
    return reduce(
      lambda (ax,ay,aw,ah), (bx,by,bw,bh):
        (min(ax,bx), min(ay,by), max(ax+aw, bx+bw), max(ay+ah, by+bh)
      ), 
      rects
    )
person dresende    schedule 06.01.2012
comment
Есть ли причина не выделять переменную? Я считаю, что для длинных строк назначение хорошего имени некоторому результату делает код более очевидным. Плюс функция местных жителей довольно дешевая. - person Petr Viktorin; 06.01.2012
comment
Нет причин вообще. Это личный выбор, как и разделение длинных очередей. Обычно я предпочитаю иметь хорошее имя функции, которое должно описывать, что она делает (в имени или в комментариях выше). - person dresende; 12.01.2012

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

def rects_bound(rects):
    """ Returns a rectangle that bounds all given rectangles
    """
    def bound_2_rects((ax, ay, aw, ah), (bx, by, bw, bh)):
        x = min(ax, bx)
        y = min(ay, by)
        return x, y, max(ax+aw, bx+bw) - x, max(ay+ah, by+bh) - y

    return reduce(bound_2_rects, rects)
person John Machin    schedule 06.01.2012

Я бы предложил следующее:

def rects_bound(rects):
    """ Returns a rectangle that bounds all given rectangles
    """
    return reduce(lambda (X,Y,W,H), (x,y,w,h): (min(X,x), min(Y,y),
                                                max(X+W, x+w),
                                                max(Y+H, y+h)), rects)

Сокращение каждого аргумента до одного символа действительно экономит место, что помогает выглядеть чище. Другим вариантом было бы определить лямбда-функцию в отдельной строке (возможно, даже с def), чтобы в первую очередь аргументы не были слишком большими.

person Andrew Clark    schedule 06.01.2012
comment
@JohnMachin - Хороший вопрос, добавил дополнительную строку, чтобы сократить ее. - person Andrew Clark; 06.01.2012
comment
Это по-прежнему некрасиво: отступ не имеет ничего общего со структурой синтаксиса; похоже, это основано исключительно на том, что строки не слишком длинные. - person John Machin; 06.01.2012
comment
@JohnMachin - отступ сразу после открывающих скобок в кортеже является стандартным для длинных строк. - person Andrew Clark; 06.01.2012