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


TL; DR какой из них самый лучший?

1.- [r.update(r.pop('some_key')) for r in res if r.get('some_key')]

2.- map(lambda r: r.update(r.pop('some_key') if r.get('some_key') else []), res)

3.- map(lambda r: r.update(r.pop('some_key')), filter(lambda r: r.get('some_key'), res))

4.- for r in res:
        if r.get('some_key'):
            for element in r['some_key']:
                r[element] = r['some_key'][element]
            del r['some_key']

5.- Insert your own approach here

Примечание : это не производственный код. Это код, который выполняется в тестовом наборе, поэтому я больше беспокоюсь о удобочитаемости/ремонтопригодности, чем о производительности. Тем не менее, я также хотел бы знать, изменится ли решение относительно того, что лучше (учет компромисса производительности/удобочитаемости), если это будет производственный код. Число элементов "some_key" довольно мало, если это имеет значение.

Контекст : у меня есть прочитайте Python List Comprehension Vs. Map , где принятый ответ гласит:

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

Тем не менее, общепринятый ответ на является ли Питоническим использовать понимание списка только для побочных эффектов? говорит:

Это очень антипифонически, чтобы сделать это [использовать списки понимания только для побочных эффектов, игнорирование возвращаемого значения], и любой опытный питонист устроит вам ад за это. Промежуточный список отбрасывается после его создания, и он потенциально может быть очень, очень большим, и поэтому дорогим для создания.

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

2 ответа:

1.- [r.update(r.pop('some_key')) for r in res if r.get('some_key')]

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

2.- map(lambda r: r.update(r.pop('some_key') if r.get('some_key') else []), res)

Не сильно отличается от 1, за исключением того, что это сломается в Py 3.X.

3.- map(lambda r: r.update(r.pop('some_key')), filter(lambda r: r.get('some_key'), res))

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

4.- for r in res:
        if r.get('some_key'):
            for element in r['some_key']:
                r[element] = r['some_key'][element]
            del r['some_key']

Это лучше, чем все остальное

  1. не генерируется ненужный список, который будет отброшен
  2. будет работать в Py 3.x
  3. нет явных накладных расходов на вызов функции
[8]}5.- Вставьте сюда свой собственный подход
    for r in res:
        if 'some_key' in r:
            r.update(r['some_key'])
            del r['some_key']

Я думаю, что этот вариант ответа Абхиджита, который в то же время является вариантом моего 4-го пункта, является лучшим.

for r in res:
    r.update(r.pop('some_key', {}))
  • имеет все преимущества использования регулярного цикла for
  • легко понять
  • занимает всего 2 строки кода
  • не нуждается в предложении if