Генераторы списков

Введение

Примеры

  • 253

    Список Пониманий

    Список понимание создает новый list , применяя выражение к каждому элементу Iterable . Наиболее простой формой является:

     [ <expression> for <element> in <iterable> ]
    
     

    Также есть необязательное условие if:

     [ <expression> for <element> in <iterable> if <condition> ]
    
     

    Каждый <element> в <iterable> подключен к <expression> если (необязательно) <condition> оценивается как истина . Все результаты сразу возвращаются в новый список. Генератор выражение вычисляется лениво, но списочные оценить весь итератор сразу - потребляя память , пропорциональную длину итератора.

    Для того, чтобы создать list квадратов целых чисел:

     squares = [x * x for x in (1, 2, 3, 4)]
    # squares: [1, 4, 9, 16]
    
     

    for выражения устанавливает x для каждого значения в свою очередь , из (1, 2, 3, 4) . Результат выражения x * x добавляются к внутреннему list . Внутренний list присваиваются переменными squares , когда завершено.

    Помимо увеличения скорости (как описано здесь ), список понимание примерно эквивалентно следующее для цикла:

     squares = []
    for x in (1, 2, 3, 4):
        squares.append(x * x)
    # squares: [1, 4, 9, 16]
    
     

    Выражение, применяемое к каждому элементу, может быть настолько сложным, насколько это необходимо:

     # Get a list of uppercase characters from a string
    [s.upper() for s in "Hello World"]
    # ['H', 'E', 'L', 'L', 'O', ' ', 'W', 'O', 'R', 'L', 'D']
    
    # Strip off any commas from the end of strings in a list
    [w.strip(',') for w in ['these,', 'words,,', 'mostly', 'have,commas,']]
    # ['these', 'words', 'mostly', 'have,commas']
    
    # Organize letters in words more reasonably - in an alphabetical order
    sentence = "Beautiful is better than ugly"
    ["".join(sorted(word, key = lambda x: x.lower())) for word in sentence.split()]
    # ['aBefiltuu', 'is', 'beertt', 'ahnt', 'gluy']
    
     

    еще

    else может быть использован в списке понимание конструкций, но быть осторожными в отношении синтаксиса. Если / иначе пункты должны быть использованы до for цикла, а не после того, как :

     # create a list of characters in apple, replacing non vowels with '*'
    # Ex - 'apple' --> ['a', '*', '*', '*' ,'e']
    
    [x for x in 'apple' if x in 'aeiou' else '*']
    #SyntaxError: invalid syntax
    
    # When using if/else together use them before the loop
    [x if x in 'aeiou' else '*' for x in 'apple']
    #['a', '*', '*', '*', 'e']
    
     

    Обратите внимание , это использует различные конструкции языка, а условное выражение , которое само по себе не является частью синтаксиса понимания . В то время как , if после того , как for…in это часть списковых и используются для фильтрации элементов из источника итерации.


    Двойная итерация

    Порядок двойной итерации [... for x in ... for y in ...] является естественным или нелогичным. Правило заключается в том , чтобы следовать эквивалент for цикла:

     def foo(i):
        return i, i + 0.5
    
    for i in range(3):
        for x in foo(i):
            yield str(x)
    
     

    Это становится:

     [str(x)
        for i in range(3)
            for x in foo(i)
    ]
    
     

    Это может быть сжат в одну линию , как [str(x) for i in range(3) for x in foo(i)]


    Мутация на месте и другие побочные эффекты

    Перед использованием списка понимания, понять разницу между функциями , вызываемыми для их побочных эффектов (Mutating, или в месте функции) , которые , как правило , не возвращают None , и функции , которые возвращают интересное значение.

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

    list.sort() сортирует список на месте ( это означает , что он изменяет первоначальный список) и не возвращает значение None . Следовательно, он не будет работать так, как ожидалось при понимании списка:

     [x.sort() for x in [[2, 1], [4, 3], [0, 1]]]
    # [None, None, None]
    
     

    Вместо sorted() возвращает отсортированный list , а не сортировку на месте:

     [sorted(x) for x in [[2, 1], [4, 3], [0, 1]]]
    # [[1, 2], [3, 4], [0, 1]]
    
     

    Возможно использование понимания побочных эффектов, таких как ввод / вывод или функции на месте. Тем не менее цикл for обычно более читабелен. Пока это работает в Python 3:

     [print(x) for x in (1, 2, 3)]
    
     

    Вместо этого используйте:

     for x in (1, 2, 3):
        print(x)
    
     

    В некоторых ситуациях, побочные функции эффекта подходят для списка понимания. random.randrange() имеет побочный эффект изменения состояния генератора случайных чисел, но она также возвращает интересное значение. Кроме того, в next() может быть вызван итератора.

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

     from random import randrange
    [randrange(1, 7) for _ in range(10)]
    # [2, 3, 2, 1, 1, 5, 2, 4, 3, 5]
    
     

    Пробелы в списках

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

     [
        x for x
        in 'foo'
        if x not in 'bar'
    ]
    
     
  • 62

    Словарь понятий

    Словарь понимание похоже на список понимание исключения того, что он создает объект словаря вместо списка.

    Основной пример:

     {x: x * x for x in (1, 2, 3, 4)}
    # Out: {1: 1, 2: 4, 3: 9, 4: 16}
    
     

    это просто еще один способ написания:

     dict((x, x * x) for x in (1, 2, 3, 4))
    # Out: {1: 1, 2: 4, 3: 9, 4: 16}
    
     

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

     {name: len(name) for name in ('Stack', 'Overflow', 'Exchange') if len(name) > 6}  
    # Out: {'Exchange': 8, 'Overflow': 8}
    
     

    Или переписать с помощью выражения генератора.

     dict((name, len(name)) for name in ('Stack', 'Overflow', 'Exchange') if len(name) > 6)
    # Out: {'Exchange': 8, 'Overflow': 8}
    
     

    Начиная со словаря и используя словарь в качестве фильтра пары ключ-значение

     initial_dict = {'x': 1, 'y': 2}
    {key: value for key, value in initial_dict.items() if key == 'x'}
    # Out: {'x': 1}
    
     

    Ключ переключения и значение словаря (инвертировать словарь)

    Если у вас есть Dict , содержащий простые hashable значения (дублирует значение может привести к неожиданным результатам):

     my_dict = {1: 'a', 2: 'b', 3: 'c'}
    
     

    и вы хотели поменять местами ключи и значения, вы можете использовать несколько подходов в зависимости от вашего стиля кодирования:

    • swapped = {v: k for k, v in my_dict.items()}
    • swapped = dict((v, k) for k, v in my_dict.iteritems())
    • swapped = dict(zip(my_dict.values(), my_dict))
    • swapped = dict(zip(my_dict.values(), my_dict.keys()))
    • swapped = dict(map(reversed, my_dict.items()))
     print(swapped)
    # Out: {a: 1, b: 2, c: 3}
    
     

    Если ваш словарь велик, рассмотрит импортирование itertools и использовать izip или imap .

    Слияние словарей

    Объедините словари и, при необходимости, переопределите старые значения с помощью вложенного словарного понимания.

     dict1 = {'w': 1, 'x': 1}
    dict2 = {'x': 2, 'y': 2, 'z': 2}
    
    {k: v for d in [dict1, dict2] for k, v in d.items()}
    # Out: {'w': 1, 'x': 2, 'y': 2, 'z': 2}
    
     

    Тем не менее, словарь распаковки ( РЕР 448 ) , может быть предпочтительным.

     {**dict1, **dict2}
    # Out: {'w': 1, 'x': 2, 'y': 2, 'z': 2}
    
     

    Примечание: словарь постижения были добавлены в Python 3.0 и портированные к 2.7+, в отличии от списковых, которые были добавлены в 2,0. Версии <2,7 можно использовать выражение генератора и dict() предопределённый имитировать поведение словаря постижений.

  • 24

    Выражения генератора

    Выражения генератора очень похожи на списки. Основное отличие состоит в том, что он не создает полный набор результатов сразу; он создает объект генератора , который затем может перемещаться.

    Например, посмотрите разницу в следующем коде:

     # list comprehension
    [x**2 for x in range(10)]
    # Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    
     
    # понимание генератора (x ** 2 для x в xrange (10)) # Вывод: в 0x11b4b7c80>

    Это два совершенно разных объекта:

    • список понимание возвращает list объектов , тогда как постижение генератор возвращает generator .

    • generator объекты не могут быть проиндексированы и используют next функцию , чтобы получить детали в порядке.

    Примечание: Мы используем xrange , так как он тоже создает объект генератора. Если бы мы использовали диапазон, список был бы создан. Кроме того , xrange существует только в более поздней версии питона 2. В Python 3, range просто возвращает генератор. Для получения дополнительной информации см Различия между функциями дальности и xrange например .


    g = (x ** 2 для x в xrange (10)) print (g [0]) Traceback (most recent call last): File "", line 1, in TypeError: 'generator' object has no attribute '__getitem__'
    g.next() # 0 g.next() # 1 g.next() # 4 ... g.next() # 81 g.next() # Throws StopIteration Exception Traceback (последний вызов был последним): File " ", строка 1, в StopIteration > ПРИМЕЧАНИЕ: функция `g.next ()` должна быть заменена на `next (g)` и `xrange` на` range`, так как `Iterator.next ()` и `xrange ()` не существуют в Python 3 ,

    Хотя оба из них могут быть повторены аналогичным образом:

     for i in [x**2 for x in range(10)]:
        print(i)
    
    """
    Out:
    0
    1
    4
    ...
    81
    """
     

    для i in (x ** 2 для x в xrange (10)): печать (i)

     """
    Out:
    0
    1
    4
    .
    .
    .
    81
    """
     

    Случаи применения

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

     for square in (x**2 for x in range(1000000)):
        #do something
    
     

    Другой распространенный вариант использования - избегать повторения всей итерации, если это не требуется. В этом примере элемент извлекается из удаленного API с каждой итерации get_objects() . Тысячи объектов могут существовать, должны быть найдены один за другим, и нам нужно только знать, существует ли объект, соответствующий шаблону. Используя выражение генератора, когда мы встречаем объект, соответствующий шаблону.

     def get_objects():
        """Gets objects from an API one by one"""
        while True:
            yield get_next_item()
    
    def object_matches_pattern(obj):
        # perform potentially complex calculation
        return matches_pattern
    
    def right_item_exists():
        items = (object_matched_pattern(each) for each in get_objects())
        for item in items:
            if item.is_the_right_one:
    
    
                return True
        return False
    
    
     
  • 21

    Установить понимание

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

     # A set containing every value in range(5):
    {x for x in range(5)}
    # Out: {0, 1, 2, 3, 4}
    
    # A set of even numbers between 1 and 10:
    {x for x in range(1, 11) if x % 2 == 0}
    # Out: {2, 4, 6, 8, 10}
    
    # Unique alphabetic characters in a string of text:
    text = "When in the Course of human events it becomes necessary for one people..."
    {ch.lower() for ch in text if ch.isalpha()}
    # Out: set(['a', 'c', 'b', 'e', 'f', 'i', 'h', 'm', 'l', 'o',
    #           'n', 'p', 's', 'r', 'u', 't', 'w', 'v', 'y'])
    
     

    Live Demo

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

    Примечание: Установить понимание доступно , так как питон 2.7+, в отличие от списковых, которые были добавлены в 2,0. В Python 2.2 на Python 2.6, то set() функция может быть использована с выражением генератора для получения того же результата:

     set(x for x in range(5))
    # Out: {0, 1, 2, 3, 4}
    
     
  • 261

    Условные списки

    Учитывая список понимание вы можете добавить один или несколько , if условия для фильтрации значений.

     [<expression> for <element> in <iterable> if <condition>]
    
     

    Для каждого <element> в <iterable> ; если <condition> имеет значение True , добавить <expression> (обычно функция <element> ) в возвращаемом списке.


    Например, это можно использовать для извлечения только четных чисел из последовательности целых чисел:

     [x for x in range(10) if x % 2 == 0]
    # Out: [0, 2, 4, 6, 8]
    
     

    Live демо

    Приведенный выше код эквивалентен:

     even_numbers = [] 
    for x in range(10):
        if x % 2 == 0:
            even_numbers.append(x)
    
    print(even_numbers)
    # Out: [0, 2, 4, 6, 8]
    
     

    Кроме того , условное список понимание вида [e for x in y if c] , e c x list(filter(lambda x: c, map(lambda x: e, y))) [e for x in y if c] (где e и c являются выражениями в терминах x ) эквивалентно list(filter(lambda x: c, map(lambda x: e, y))) - list(filter(lambda x: c, map(lambda x: e, y))) - list(filter(lambda x: c, map(lambda x: e, y))) .

    Несмотря на предоставление того же результата, обратите внимание на тот факт, что первый пример почти в 2 раза быстрее, чем второй. Для тех , кому любопытно, это хорошее объяснение причин почему.


    Обратите внимание , что это совершенно отличается от ... if ... else ... условного выражения (иногда известное как трехкомпонентное выражение ) , которые вы можете использовать для <expression> часть списка понимания. Рассмотрим следующий пример:

     [x if x % 2 == 0 else None for x in range(10)]
    # Out: [0, None, 2, None, 4, None, 6, None, 8, None]
    
     

    Live демо

    Здесь условное выражение - не фильтр, а оператор, определяющий значение, которое будет использоваться для элементов списка:

     <value-if-condition-is-true> if <condition> else <value-if-condition-is-false>
    
     

    Это становится более очевидным, если вы объедините его с другими операторами:

     [2 * (x if x % 2 == 0 else -1) + 1 for x in range(10)]
    # Out: [1, -1, 5, -1, 9, -1, 13, -1, 17, -1]
    
     

    Live демо

    Если вы используете Python 2.7, xrange может быть лучше , чем range по нескольким причинам , как описано в xrange документации .

     [2 * (x if x % 2 == 0 else -1) + 1 for x in xrange(10)]
    # Out: [1, -1, 5, -1, 9, -1, 13, -1, 17, -1]
    
     

    Приведенный выше код эквивалентен:

     numbers = []
    for x in range(10):
        if x % 2 == 0:
            temp = x
        else:
            temp = -1
        numbers.append(2 * temp + 1)
    print(numbers)
    # Out: [1, -1, 5, -1, 9, -1, 13, -1, 17, -1]
    
     

    Можно комбинировать тройные выражения и if условия. Тернарный оператор работает с отфильтрованным результатом:

     [x if x > 2 else '*' for x in range(10) if x % 2 == 0]
    # Out: ['*', '*', 4, 6, 8]
    
     

    То же самое не могло быть достигнуто только одним троичным оператором:

     [x if (x > 2 and x % 2 == 0) else '*' for x in range(10)]
    # Out:['*', '*', '*', '*', 4, '*', 6, '*', 8, '*']
     

    Смотрите также: фильтры , которые часто обеспечивают достаточную альтернативу условных списковые.

  • 173

    Избегайте повторяющихся и дорогостоящих операций с использованием условного предложения

    Рассмотрим следующее понимание списка:

     >>> def f(x):
    ...     import time
    ...     time.sleep(.1)       # Simulate expensive function
    ...     return x**2
    
    >>> [f(x) for x in range(1000) if f(x) > 10]
    [16, 25, 36, ...]
    
    
     

    Это приводит к двум вызовами f(x) для 1000 значений x : один вызов для генерации значения , а другой для проверки , if это условие. Если f(x) является особенно дорогостоящей операцией, это может существенно влиять на производительность. Хуже того , если вы звоните f() имеет побочные эффекты, это может иметь неожиданные результаты.

    Вместо этого, вы должны оценить дорогостоящую операцию только один раз для каждого значения x путем генерации промежуточного Iterable ( выражение генератора ) следующим образом :

     >>> [v for v in (f(x) for x in range(1000)) if v > 10]
    [16, 25, 36, ...]
    
     

    Или, используя встроенную карту эквивалент:

     >>> [v for v in map(f, range(1000)) if v > 10]
    [16, 25, 36, ...]
    
    
     

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

     >>> [v for x in range(1000) for v in [f(x)] if v > 10]
    [16, 25, 36, ...]
    
     

    Однако на практике логика кода может быть более сложной, и важно, чтобы она была читабельной. В общем, отдельные генератор функции рекомендуются более сложным однострочник:

    >>> def process_prime_numbers(iterable):
    ...     for x in iterable:
    ...         if is_prime(x):
    ...             yield f(x)
    ...
    >>> [x for x in process_prime_numbers(range(1000)) if x > 10]
    [11, 13, 17, 19, ...]
    
    
    

    Другой способ предотвращения вычислений f(x) несколько раз, чтобы использовать @functools.lru_cache() (Python 3.2+) декоратор на f(x) . Таким образом , так как выход из f для входного x уже вычислен один раз, второй вызов функции из исходного списка понимания будет так быстро , как поиск в словаре. Этот подход использует мемоизация для повышения эффективности, что сопоставимо с использованием выражений генератора.


    Скажем, вы должны сгладить список

     l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
    
     

    Некоторые из методов могут быть:

     reduce(lambda x, y: x+y, l)
    
    sum(l, [])
    
    list(itertools.chain(*l))
    
     

    Однако понимание списка обеспечит лучшую временную сложность.

     [item for sublist in l for item in sublist]
    
     

    Ярлыки, основанные на + (включая подразумеваемое использование в сумме), по необходимости, O (L ^ 2), когда есть L подсписков - поскольку список промежуточных результатов продолжает увеличиваться, на каждом шаге новый объект списка промежуточных результатов получает выделены, и все элементы в предыдущем промежуточном результате должны быть скопированы (а также несколько новых добавлены в конце). Поэтому (для простоты и без фактической потери общности) скажем, что у вас есть L подсписков из I элементов каждый: первые I элементы копируются туда-сюда L-1 раз, вторые I-элементы L-2 раза и т. Д .; общее количество копий равно I, умноженному на сумму x для x от 1 до L, т.е. I * (L ** 2) / 2.

    Понимание списка только генерирует один список, один раз, и копирует каждый элемент (из его первоначального места жительства в список результатов) также ровно один раз.

  • 49

    Перечень списков с помощью вложенных циклов

    Списковые может использовать вложенный for петель. Вы можете закодировать любое количество вложенных циклов для внутри списка понимания, и каждый for цикла может иметь дополнительный связанный , if тест. При этом порядок следования for построений такой же порядок , как при написании серии вложенных for заявлений. Общая структура списочных представлений выглядит следующим образом:

     [ expression for target1 in iterable1 [if condition1]
                 for target2 in iterable2 [if condition2]...
                 for targetN in iterableN [if conditionN] ]
    
     

    Например, следующий код уплощение списка списков с использованием нескольких for операторов:

     data = [[1, 2], [3, 4], [5, 6]]
    output = []
    for each_list in data:
        for element in each_list:
            output.append(element)
    print(output)
    # Out: [1, 2, 3, 4, 5, 6]
    
     

    может быть эквивалентно записать в виде списка осмыслению с кратному for конструкций:

     data = [[1, 2], [3, 4], [5, 6]]
    output = [element for each_list in data for element in each_list]
    print(output)
    # Out: [1, 2, 3, 4, 5, 6]
    
     

    Live Demo

    Как в расширенной форме, так и в понимании списка, внешний цикл (первый для оператора) идет первым.


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

     In [1]: data = [[1,2],[3,4],[5,6]]
    In [2]: def f():
       ...:     output=[]
       ...:     for each_list in data:
       ...:         for element in each_list:
       ...:             output.append(element)
       ...:     return output
    In [3]: timeit f()
    1000000 loops, best of 3: 1.37 µs per loop
    In [4]: timeit [inner for outer in data for inner in outer]
    1000000 loops, best of 3: 632 ns per loop
    
     

    Накладные расходы на вызов функции выше примерно 140ns.


    Встроенный , if ы вложены подобным образом , и может происходить в любом положении после первого for :

     data = [[1], [2, 3], [4, 5]]
    output = [element for each_list in data
                    if len(each_list) == 2
                    for element in each_list
                    if element != 5]
    print(output)
    # Out: [2, 3, 4]
    
     

    Live Demo

    Ради удобства чтения, однако, вы должны рассмотреть возможность использования традиционного для петель. Это особенно верно, когда вложение глубиной более 2-х уровней и / или логика понимания слишком сложна. многократное понимание списка вложенных циклов может быть подвержено ошибкам или дает неожиданный результат.

  • 17

    Фильтр рефакторинга и карта для отображения списка

    В filter или map функция часто должно быть заменена списковыми . Гвидо ван Россум описывает это хорошо в открытом письме в 2005 году :

    filter(P, S) почти всегда написан яснее , как [x for x in S if P(x)] , x==42 [x for x in S if P(x)] , и это имеет огромное преимущество , что наиболее распространенные обычаи привлечения предикатов , которые являются сравнением, например , x==42 , а также определение лямбда для этого просто требует гораздо больше усилий для читателя (плюс лямбда медленнее, чем понимание списка). Тем более , что для map(F, S) , который становится [F(x) for x in S] . Конечно, во многих случаях вы могли бы использовать вместо этого выражения генератора.

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

     filter(lambda x: x % 2 == 0, range(10)) # even numbers < 10
    map(lambda x: 2*x, range(10)) # multiply each number by two
    reduce(lambda x,y: x+y, range(10)) # sum of all elements in list
    
     

    Принимая то , что мы узнали из предыдущей цитаты, мы можем сломать эти filter и map выражения в эквивалентных им списковые; также удаление лямбда - функции от каждого - сделать код более читаемым в этом процессе.

     # Filter:
    # P(x) = x % 2 == 0
    # S = range(10)
    [x for x in range(10) if x % 2 == 0]
    
    # Map
    # F(x) = 2*x
    # S = range(10)
    [2*x for x in range(10)]
    
     

    Читаемость становится еще более очевидной при работе с функциями цепочки. Где из-за читабельности, результаты одной карты или функции фильтра должны быть переданы в качестве результата следующей; в простых случаях их можно заменить на понимание единого списка. Кроме того, мы можем легко понять из понимания списка, каков результат нашего процесса, где существует большая когнитивная нагрузка при рассуждениях о цепочечном процессе Map & Filter.

     # Map & Filter
    filtered = filter(lambda x: x % 2 == 0, range(10))
    results = map(lambda x: 2*x, filtered)
    
    # List comprehension
    results = [2*x for x in range(10) if x % 2 == 0]
    
     

    Рефакторинг - краткий справочник

    • карта

       map(F, S) == [F(x) for x in S] 
    • Фильтр

       filter(P, S) == [x for x in S if P(x)] 

    где F и P являются функциями , которые соответственно преобразуют входные значения и возвращают bool

  • 10

    Понимания с участием кортежей

    for пункта в список понимания можно указать более одной переменные:

     [x + y for x, y in [(1, 2), (3, 4), (5, 6)]]
    # Out: [3, 7, 11]
    
    [x + y for x, y in zip([1, 3, 5], [2, 4, 6])]
    # Out: [3, 7, 11]
    
     

    Это так же , как регулярные for петель:

     for x, y in [(1,2), (3,4), (5,6)]:
        print(x+y)
    # 3
    # 7
    # 11
    
     

    Однако обратите внимание, что если выражение, начинающее понимание, является кортежем, его необходимо заключить в скобки:

     [x, y for x, y in [(1, 2), (3, 4), (5, 6)]]
    # SyntaxError: invalid syntax
    
    [(x, y) for x, y in [(1, 2), (3, 4), (5, 6)]]
    # Out: [(1, 2), (3, 4), (5, 6)]
    
     
  • 7

    Подсчет вхождений с использованием понимания

    Когда мы хотим подсчитать количество элементов в итерируемом элементе, которые удовлетворяют некоторому условию, мы можем использовать понимание для создания идиоматического синтаксиса:

     # Count the numbers in `range(1000)` that are even and contain the digit `9`:
    print (sum(
        1 for x in range(1000) 
        if x % 2 == 0 and
        '9' in str(x)
    ))
    # Out: 95
    
     

    Основная концепция может быть обобщена как:

    1. Итерации над элементами в range(1000) .
    2. Сцепить все необходимое , if условия.
    3. Используйте 1 в качестве выражения для возврата 1 для каждого элемента , который соответствует условиям.
    4. Суммируем все 1 с , чтобы определить количество элементов , которые удовлетворяют условиям.

    Примечание: Здесь мы не сбор 1 сек в списке (обратите внимание на отсутствие квадратных скобок), но мы проходим те непосредственно к sum функции , которая подводит их. Это называется выражение генератора, который похож на Comprehension.

  • 4

    Изменение типов в списке

    Количественные данные часто считываются в виде строк, которые должны быть преобразованы в числовые типы перед обработкой. Типы всех элементов списка могут быть преобразованы либо в списке Comprehension или map() функцию .

    # Convert a list of strings to integers.
    items = ["1","2","3","4"]
    [int(item) for item in items]
    # Out: [1, 2, 3, 4]
    
    # Convert a list of strings to float.
    items = ["1","2","3","4"]
    map(float, items)
    # Out:[1.0, 2.0, 3.0, 4.0] 
    
    
  • 3

    Понимание вложенного списка

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

     #List Comprehension with nested loop
    [x + y for x in [1, 2, 3] for y in [3, 4, 5]]
    #Out: [4, 5, 6, 5, 6, 7, 6, 7, 8]
    
    #Nested List Comprehension
    [[x + y for x in [1, 2, 3]] for y in [3, 4, 5]]
    #Out: [[4, 5, 6], [5, 6, 7], [6, 7, 8]]
    
     

    Вложенный пример эквивалентен

     l = []
    for y in [3, 4, 5]:
        temp = []
        for x in [1, 2, 3]:
            temp.append(x + y)
        l.append(temp)
    
     

    Один пример, где вложенное понимание может быть использовано для транспонирования матрицы.

     matrix = [[1,2,3],
              [4,5,6],
              [7,8,9]] 
    
    [[row[i] for row in matrix] for i in range(len(matrix))]
    # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
    
     

    Как и вложенные for петель, есть не предел того , как глубоко постижения могут быть вложенными.

     [[[i + j + k for k in 'cd'] for j in 'ab'] for i in '12']
    # Out: [[['1ac', '1ad'], ['1bc', '1bd']], [['2ac', '2ad'], ['2bc', '2bd']]] 
  • 3

    Итерация двух или более списков одновременно в пределах понимания списка

    Для перебора более двух списков одновременно в списке понимания, можно использовать zip() , как:

     >>> list_1 = [1, 2, 3 , 4]
    >>> list_2 = ['a', 'b', 'c', 'd']
    >>> list_3 = ['6', '7', '8', '9']
    
    # Two lists
    >>> [(i, j) for i, j in zip(list_1, list_2)]
    [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]
    
    # Three lists
    >>> [(i, j, k) for i, j, k in zip(list_1, list_2, list_3)]
    [(1, 'a', '6'), (2, 'b', '7'), (3, 'c', '8'), (4, 'd', '9')]
    
    # so on ...
    
    
     

Синтаксис

Параметры

Примечания