Использование 'in' для сопоставления атрибута объектов Python в массиве

Я не помню, мечтал я или нет, но, похоже, я помню, что есть функция, которая позволяла что-то вроде

foo in iter_attr(array of python objects, attribute name)

Я просмотрел документы, но такие вещи не попадают под какие-либо очевидные заголовки.

Ответ 1

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

Временного списка можно избежать с помощью выражения генератора:

foo = 12
foo in (obj.id for obj in bar)

Теперь, пока obj.id == 12 ближе к началу bar, поиск будет быстрым, даже если bar бесконечно длинный.

Как предложил @Matt, рекомендуется использовать hasattr, если какой-либо из объектов в bar может отсутствовать атрибут id:

foo = 12
foo in (obj.id for obj in bar if hasattr(obj, 'id'))

Ответ 2

Вы хотите получить список объектов с определенным атрибутом? Если это так, понимание списка - это правильный способ сделать это.

result = [obj for obj in listOfObjs if hasattr(obj, 'attributeName')]

Ответ 3

вы всегда можете написать один:

def iterattr(iterator, attributename):
    for obj in iterator:
        yield getattr(obj, attributename)

будет работать со всем, что итерации, будь то кортеж, список или что-то еще.

Мне нравится python, он делает такие вещи такими же простыми и не более сложными, чем необходимо, и использовать такие вещи, как это, очень элегантно.

Ответ 4

Нет, вы не мечтали. Python имеет довольно отличную систему распознавания списков, которая позволяет вам управлять списками довольно элегантно, и в зависимости от того, что вы хотите выполнить, это можно сделать несколькими способами. В сущности, вы делаете: "Для элемента в списке if criteria.matches", и из этого вы можете просто перебирать результаты или выгружать результаты в новый список.

Я собираюсь сделать здесь пример из Dive Into Python, потому что он довольно элегантный, и они умнее, чем я. Здесь они получают список файлов в каталоге, а затем фильтруют список для всех файлов, которые соответствуют критериям регулярного выражения.

    files = os.listdir(path)                               
    test = re.compile("test\.py$", re.IGNORECASE)          
    files = [f for f in files if test.search(f)]

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

Эрик Сипл

Ответ 5

Функция, о которой вы думаете, вероятно, operator.attrgettter. Например, чтобы получить список, содержащий значение атрибута "id" каждого объекта:

import operator
ids = map(operator.attrgetter("id"), bar)

Если вы хотите проверить, содержит ли список объект с идентификатором == 12, то аккуратный и эффективный (т.е. не перебирает весь список без необходимости) способ сделать это:

any(obj.id == 12 for obj in bar)

Если вы хотите использовать 'in' с attrgetter, сохраняя при этом ленивую итерацию списка:

import operator,itertools
foo = 12
foo in itertools.imap(operator.attrgetter("id"), bar)

Ответ 6

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

то есть. "bar" - это список объектов, все из которых имеют атрибут "id"

Мифический функциональный способ:

foo = 12
foo in iter_attr(bar, 'id')

Способ понимания списка:

foo = 12
foo in [obj.id for obj in bar]

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

Ответ 7

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

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

Помните, что у python есть один из самых эффективных алгоритмов хэширования. Используйте его в своих интересах.

Ответ 8

Я думаю:

#!/bin/python
bar in dict(Foo)

Это то, о чем вы думаете. Когда вы пытаетесь определить, существует ли какой-либо ключ в словаре в python (версия хэширования python), есть два способа проверить. Сначала применяется метод has_key(), подключенный к словарю, а второй - приведенный выше пример. Он вернет логическое значение.

Это должно ответить на ваш вопрос.

А теперь немного не по теме, чтобы связать это с ответом на список, который ранее давался (для немного большей ясности). List Comprehensions строят список из базового цикла с модификаторами. В качестве примера (чтобы немного пояснить) можно использовать конструкцию языка in dict в понимании списка:

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

#!/bin/python
baz = dict([(key, value) for key, value in foo if bar in value])

Обратите внимание на if bar in value в конце инструкции **, это предложение модификации, которое говорит, что понимание списка содержит только те пары ключ-значение, которые удовлетворяют условию. ** В этот случай baz - это новый словарь, содержащий только словари из foo, содержащие бар (надеюсь, что я не пропустил ничего в этом примере кода... вам, возможно, придется взглянуть на список, содержащийся в docs.python.org tutorials и secnetix.de, оба сайта являются хорошими ссылками, если у вас есть вопросы в будущем.).