Вхідний цикл Python, якому передує змінна


77
foo = [x for x in bar if x.occupants > 1]

Погугливши та шукаючи тут, не міг зрозуміти, що це робить. Можливо, я не шукав потрібні речі, але ось вони. Будь-який внесок у розвінчання цієї стенографії дуже вдячний.


6
@Greg, я погуглив, python "* for * in * if"і це був перший хіт secnetix.de/olli/Python/list_comprehension.hawk
Джон Ла Рой,

Відповіді:


84

Поточні відповіді хороші, але не варто говорити про те, як вони є просто синтаксичним цукром за якоюсь схемою, до якої ми так звикли.

Почнемо з прикладу, скажімо, у нас є 10 чисел, і ми хочемо підмножину тих, які більші, ніж, скажімо, 5.

>>> numbers = [12, 34, 1, 4, 4, 67, 37, 9, 0, 81]

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

Підхід 1

result = []
for index in range(len(numbers)):
    if numbers[index] > 5:
        result.append(numbers[index])
print result  #Prints [12, 34, 67, 37, 9, 81]

Підхід 2 (трохи чистіший, вхідні петлі)

result = []
for number in numbers:
    if number > 5:
        result.append(number)
print result  #Prints [12, 34, 67, 37, 9, 81]

Підхід 3 (введіть розуміння списку)

result = [number for number in numbers if number > 5]

або більш загально:

[function(number) for number in numbers if condition(number)]

де:

  • function(x)приймає xі перетворює його на щось корисне (як, наприклад: x*x)
  • якщо condition(x)повертає будь-яке значення False-y (False, None, порожній рядок, порожній список тощо), тоді поточна ітерація буде пропущена (подумайте continue). Якщо функція повертає значення, яке не є False-y, тоді поточне значення потрапляє до остаточного результуючого масиву (і проходить крок перетворення вище).

Щоб зрозуміти синтаксис дещо по-іншому, перегляньте розділ "Бонус" нижче.

Для отримання додаткової інформації дотримуйтесь посібника, на який зв’язані всі інші відповіді: Список розуміння


Бонус

(Трохи непітонічний, але розміщуючи його тут для повноти)

Приклад вище можна записати так:

result = filter(lambda x: x > 5, numbers)

Загальний вираз вище можна записати так:

result = map(function, filter(condition, numbers)) #result is a list in Py2

Я б назвав перше, що взагалі вираз ; якщо це просто x*x, це може бути просто там, а не square(x). Це робить його ще болючим тоді, коли я бачу, що вираз перетворився на лямбду, наприклад [x**2 for x in range(5)]проти map(lambda x: x**2, range(5)).
Nick T

26

Це розуміння списку

fooбуде відфільтрованим списком, barщо містить об'єкти з атрибутом мешканці> 1

barможе бути list, set, dictабо будь-який інший итератор

Ось приклад для уточнення

>>> class Bar(object):
...   def __init__(self, occupants):
...     self.occupants = occupants
... 
>>> bar=[Bar(0), Bar(1), Bar(2), Bar(3)]
>>> foo = [x for x in bar if x.occupants > 1]
>>> foo
[<__main__.Bar object at 0xb748516c>, <__main__.Bar object at 0xb748518c>]

Отже, foo має 2 Barоб’єкти, але як ми можемо перевірити, які це? Давайте додамо __repr__метод, щоб Barвін був більш інформативним

>>> Bar.__repr__=lambda self:"Bar(occupants={0})".format(self.occupants)
>>> foo
[Bar(occupants=2), Bar(occupants=3)]

2
Ця відповідь суворо краща за прийняту відповідь, але не позначена як така, оскільки вона з’явилася через 4 хвилини.
user1717828

1

Наскільки я можу зрозуміти, це повинно працювати, це перевірка на те, чи порожній список "bar" (0), чи складається з одиничного елемента (1) через x.occupants, де x - визначений елемент у рядку списку, може мати характеристику мешканців. Тож foo викликається, рухається по списку, а потім повертає всі елементи, які проходять умову перевірки x.occupant.

У такій мові, як Java, ви створюєте клас під назвою "x", де об'єкти "x" потім призначаються масиву або тому подібному. X мав би поле, яке називається "мешканці", і кожен індекс перевірявся б методом x.occupants, який повертав би номер, присвоєний мешканцю. Якби цей метод повернув більше 1 (ми припускаємо, що int тут, оскільки частковий мешканець буде непарним.), Метод foo (викликаний для масиву або подібного, про який йде мова.) Тоді поверне масив або подібний, як визначено в методі foo для цього масиву контейнерів або що у вас є. Елементами поверненого масиву будуть об'єкти 'x' у першій річці масиву, які відповідають критеріям "Більше 1".

Python має вбудовані методи за допомогою розуміння списку, щоб вирішити це набагато коротше і значно спрощеніше. Замість реалізації двох повних класів та декількох методів я пишу цей рядок коду.


Див. Приклад, який я додав до своєї відповіді
Джон Ла Рой,

0

Це повертає список, який містить усі елементи в панелі, які мають мешканців> 1.


0

Оскільки на програмову частину запитання відповідають інші, приємно знати її відношення до математики ( теорії множин ). Насправді це реалізація Python нотації конструктора наборів :

Визначення набору за аксіомою специфікації :

B = {x є A: S (x)}

Англійський переклад: B - це набір, де його члени вибираються з A , тому B - це підмножина A (B ⊂ A), де характеристика (и), зазначена функцією S, виконує:S(x) == True

Визначення B за допомогою розуміння списку:

B = [x для x в A, якщо S (x)]

Отже, щоб побудувати B з розумінням списку , члени B (позначені x ) вибираються із набору A де S(x) == True(умова включення).

Примітка: Функція, Sяка повертає логічне значення, називається предикатом .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.