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

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

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

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

Ответов (8)

Решение

Использование понимания списка приведет к созданию временного списка, который может съесть всю вашу память, если просматриваемая последовательность будет большой. Даже если последовательность невелика, создание списка означает повторение всей последовательности, прежде чем 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'))

Нет, тебе не снилось. Python имеет довольно отличную систему понимания списков, которая позволяет вам довольно элегантно манипулировать списками, и в зависимости от того, чего именно вы хотите достичь, это можно сделать двумя способами. По сути, вы говорите «Для элемента в списке, если условие.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 (), но если бы я собирался выбирать, я бы пошел с этим.

Эрик Сиппл

Думаю:

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

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

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

А теперь немного не по теме, чтобы связать это с ранее приведенным ответом на понимание списка (для большей ясности). Представления списков создают список из базового цикла for с модификаторами. В качестве примера (чтобы немного уточнить) способ использования 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 и на secnetix.de , оба сайта являются хорошими ссылками, если у вас есть вопросы в будущем.).

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

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

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

т.е. bar - это список объектов, каждый из которых имеет атрибут id.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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