Являются ли представления Python списками того же самого, что и map/grep в Perl?

У меня возникли проблемы с поиском синтаксиса понимания списков в Python, поэтому я начал думать о том, как добиться того же самого в Perl, с которым я больше знаком. Я понял, что основные примеры (взятые из на этой странице) могут быть выполнены в Perl с помощью map или grep.

например.

(python)                            (perl)                  
S = [x**2 for x in range(10)]       @S = map { $_**2 } ( 0..9 );
V = [2**i for i in range(13)]       @V = map { 2**$_ } ( 0..12 );
M = [x for x in S if x % 2 == 0]    @M = grep { $_ % 2 == 0 } @S;

Итак, это "понимание списка" просто причудливый термин для "карты и/или фильтрации списка" или есть ли еще что-то?

Ответы

Ответ 1

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

Надеемся, что этот примерный код демонстрирует их равенство:

>>> # Python 2
>>> [x**2 for x in range(10)] == map(lambda x: x**2, range(10))
True
>>> [2**i for i in range(13)] == map(lambda x: 2**x, range(13))
True
>>> S = [x**2 for x in range(10)]
>>> [x for x in S if x % 2 == 0] == filter(lambda x: x % 2 == 0, S)
True

Обратите внимание, что это допустимо только в Python 2.X, как указано в комментарии SilentGhost. Чтобы сделать это совместимым с Python 3, вам придется обернуть вызовы для сопоставления или фильтрации в конструкторе list, потому что карта и фильтр были обновлены, чтобы возвращать итераторы, а не списки.

>>> # Python 3
>>> [x**2 for x in range(10)] == list(map(lambda x: x**2, range(10)))
True
>>> [2**i for i in range(13)] == list(map(lambda x: 2**x, range(13)))
True
>>> S = [x**2 for x in range(10)]
>>> [x for x in S if x % 2 == 0] == list(filter(lambda x: x % 2 == 0, S))
True

Ответ 2

Да, они в основном одинаковы.

Фактически Python также имеет функцию отображения:

S = map(lambda x: x**2, range(10))

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

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

Ответ 3

Они представляют собой "pythonic" версию для сопоставления и фильтрации последовательностей, но они позволяют делать некоторые другие вещи, например, сглаживать вложенный список (фиксированный уровень), например:

[j for i in nested_list for j in i]

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

[(x%y)*z for x,y,z in list_with_triplets_of_ints]

конечно, есть обходные пути вроде:

aux = lambda x,y,z: (x%y)*z
map(lambda t: aux(*t), list_with_triplets_of_ints)

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

map(int, list_of_str_values)

а не

[int(i) for i in list_of_str_values]

Ответ 4

Смысл списка также сглаживает вещи:

Например:

[(x, y) для x в xrange (10), если x% 2 == 0 для y в xrange (20), если x!= y]

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

Ответ 5

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

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

Ответ 6

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