Альтернативная форма тернарного оператора Python

    Недавно я открыл для себя альтернативу стандартной конструкции "expression_on_true if predicate else expression_on_false", которую я не встречал в справочниках:

    (expression_on_false, expression_on_true)[predicate]

    image

    Как это работает


    1. В круглых скобках объявляется кортеж из двух элементов.
    2. В квадратных скобках вычисляется значение предиката.
    3. Происходит обращение к кортежу по индексу 1 (если значение предиката True) или 0 (если значение предиката False)

    Разберем на примере


    Допустим, у нас есть число a, и нам надо вывести «positive», если число не меньше нуля, или «nagative», если число меньше нуля.

    
    >>> a = 101
    >>> ("negative", "positive")[a >= 0]
    'positive'
    >>> a = -42
    >>> ("negative", "positive")[a >= 0]
    'negative'
    >>> a = 0
    >>> ("negative", "positive")[a >= 0]
    'positive'
    

    В первом случае 101 >= 0, поэтому предикат возвращает True. При индексации True превращается в 1, поэтому обращение идет к элементу с индексом 1. Во втором случае аналогично: предикат равен False, обращение идет к элементу с индексом 0.

    Конструкция («negative», «positive»)[a >= 0] хоть и не намного короче чем «positive» if a >= 0 else «positive», но я все же нахожу данную фичу интересной

    Примечание


    (спасибо Dasdy)
    Если в кортеж вместо констант подставить выражения, из которых должно быть выполнено только одно, то данная конструкция теряет смысл.

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 23

      +10

      Не работает как тернарный оператор:


      (download_huge_file(), sys.exit(1))[not os.file.exists(...) and input("Файл не найден. Скачать?") == "yes"]

      Хотя даже если знать о том, что будут выполняться обе ветки выражения (до выполнения условия!), и использовать как в посте — для возврата правильного значения, будут созданы лишние обьекты.

        0
        Спасибо, этого я не учел.
          +8

          работает. лишние объекты (кроме самих лямбд) не создаются.


          (lambda: sys.exit(1), lambda: download_huge_file())[not os.path.exists('123') and input("Файл не найден. Скачать?") == "yes"]()
            +13

            Что бы так писать, нужно ну очень сильно не любить ключевые слова if/else. Но — так работает, согласен.

          +8

          Я не спец в Python, но выглядит это как кортеж на два элемента и приложенный к нему индексатор. Предполагая, что True это 1, а False это 0.
          Как уже написано выше, при создаии кортежа, скорее всего, выполнятся оба выражения, из-за чего все преимущество тернарного оператора теряется.

            +2
            это как кортеж на два элемента и приложенный к нему индексатор

            так и есть
              +5

              Можно написать


              (lambda: false_clause, lambda: true_clause)[condition]()

              , но это расточительно даже по меркам Python.

              • НЛО прилетело и опубликовало эту надпись здесь
                +1
                Предполагая, что True это 1, а False это 0.

                Это не "предполагая", а приведение типов.
                Логического к целому.

                +3

                В чем преимущество данной конструкции?

                  +7

                  Заставим perl-программистов завидовать!

                    +1
                    Скорее, «попросим высокомерно усмехнуться»
                      +4
                      Классика же из perl
                      my $max = ($x, $y)[$x < $y];
                      my $min = ($x, $y)[$x > $y];
                      

                      Оно же в Python
                      >>> x = 10
                      >>> y = 20
                      >>> max = (x, y)[x<y]
                      >>> max
                      20
                      >>> min = (x, y)[x>y]
                      >>> min
                      10
                    +5

                    Мне кажется, что любой более или менее правильно настроенный линтер кода сразу скажет переписать этот ужас.
                    Одумайтесь! Этот код потом читать людям, а не машинам.

                      +2

                      Первое апреля же на дворе (было), не переживайте.

                        +1

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

                          0

                          Ну, те кто учат язык программирования по стэковерфлоу и рандомным статьям на хабре (и даже не читают камменты) — сами себе злобные буратины, как мне кажется.

                            +2

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

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

                        Вариант с true-false это частный случай, более правильный это большее количество вариантов и полноценное целое число в качестве "ключа". Ну а если вместо кортежа взять словарь, то получится switch-case в стиле питона.

                          +1
                          Чувствуется наличие у автора прошлого в языках С/С++
                            0
                            отчасти это так
                            +2
                            Вообще говоря, очень крутая штука. Если надо будет обфусцировать код — обязательно ей воспользуюсь)

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

                            Самое читаемое