Использование 'in' для сопоставления атрибута объектов Python в массиве - PullRequest
43 голосов
/ 03 августа 2008

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

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

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

Ответы [ 8 ]

41 голосов
/ 12 сентября 2008

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

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

result = [obj for obj in listOfObjs if hasattr(obj, 'attributeName')]
10 голосов
/ 28 августа 2008

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

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

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

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

7 голосов
/ 03 августа 2008

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

Эрик Сиппл

6 голосов
/ 05 февраля 2011

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

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

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

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

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

<code>import operator,itertools
foo = 12
foo in itertools.imap(operator.attrgetter("id"), bar)
5 голосов
/ 03 августа 2008

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

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

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

foo = 12
foo in iter&#95;attr(bar, 'id')

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

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

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

3 голосов
/ 28 августа 2008

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

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

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

0 голосов
/ 03 августа 2008

Я думаю:

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...