понимание списка против лямбда + фильтр - PullRequest
740 голосов
/ 10 июня 2010

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

Мой код выглядел так:

my_list = [x for x in my_list if x.attribute == value]

Но тогда я подумал: не лучше ли написать это так?

my_list = filter(lambda x: x.attribute == value, my_list)

Это более читабельно, и если нужно для производительности, лямбда может быть извлечена, чтобы получить что-то.

Вопрос: есть ли какие-то предостережения при использовании второго способа?Есть разница в производительности?Я полностью пропускаю Pythonic Way ™ и должен сделать это еще одним способом (например, использовать itemgetter вместо лямбды)?

Ответы [ 14 ]

5 голосов
/ 28 августа 2015

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

В этом случае я читаю файл, удаляя пустые строки, закомментированныйстрок и всего, что угодно после комментария к строке:

# Throw out blank lines and comments
with open('file.txt', 'r') as lines:        
    # From the inside out:
    #    [s.partition('#')[0].strip() for s in lines]... Throws out comments
    #   filter(lambda x: x!= '', [s.part... Filters out blank lines
    #  y for y in filter... Converts filter object to list
    file_contents = [y for y in filter(lambda x: x != '', [s.partition('#')[0].strip() for s in lines])]
3 голосов
/ 28 ноября 2017

Мне потребовалось некоторое время, чтобы ознакомиться с higher order functions filter и map. Так что я привык к ним, и мне действительно понравился filter, поскольку было ясно, что он фильтрует, сохраняя все правдивое, и я чувствовал себя классно, когда знал некоторые functional programming термины.

Тогда я читаю этот отрывок (Свободная Книга Питона):

Функции карт и фильтров все еще встроены в Python 3, но с момента введения списков и генераторов давления, они не так важны. Listcomp или genexp выполняет работу карты и Фильтр комбинированный, но более читабельный.

И теперь я думаю, зачем беспокоиться о понятии filter / map, если вы можете достичь этого с помощью уже широко распространенных идиом, таких как списочное понимание. Кроме того, maps и filters являются разновидностями функций. В этом случае я предпочитаю использовать Anonymous functions лямбды.

Наконец, просто для того, чтобы протестировать его, я рассчитал оба метода (map и listComp), и я не увидел какой-либо существенной разницы в скорости, которая бы оправдывала споры по этому поводу.

from timeit import Timer

timeMap = Timer(lambda: list(map(lambda x: x*x, range(10**7))))
print(timeMap.timeit(number=100))

timeListComp = Timer(lambda:[(lambda x: x*x) for x in range(10**7)])
print(timeListComp.timeit(number=100))

#Map:                 166.95695265199174
#List Comprehension   177.97208347299602
0 голосов
/ 03 октября 2018

Любопытно, что в Python 3 фильтр работает быстрее, чем списки.

Я всегда думал, что списки будут более производительными.Примерно так: [имя для name в brand_names_db, если name не None] Сгенерированный байт-код немного лучше.

>>> def f1(seq):
...     return list(filter(None, seq))
>>> def f2(seq):
...     return [i for i in seq if i is not None]
>>> disassemble(f1.__code__)
2         0 LOAD_GLOBAL              0 (list)
          2 LOAD_GLOBAL              1 (filter)
          4 LOAD_CONST               0 (None)
          6 LOAD_FAST                0 (seq)
          8 CALL_FUNCTION            2
         10 CALL_FUNCTION            1
         12 RETURN_VALUE
>>> disassemble(f2.__code__)
2           0 LOAD_CONST               1 (<code object <listcomp> at 0x10cfcaa50, file "<stdin>", line 2>)
          2 LOAD_CONST               2 ('f2.<locals>.<listcomp>')
          4 MAKE_FUNCTION            0
          6 LOAD_FAST                0 (seq)
          8 GET_ITER
         10 CALL_FUNCTION            1
         12 RETURN_VALUE

Но на самом деле они медленнее:

   >>> timeit(stmt="f1(range(1000))", setup="from __main__ import f1,f2")
   21.177661532000116
   >>> timeit(stmt="f2(range(1000))", setup="from __main__ import f1,f2")
   42.233950221000214
0 голосов
/ 22 августа 2013

Мой дубль

def filter_list(list, key, value, limit=None):
    return [i for i in list if i[key] == value][:limit]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...