Pythonic способ доступа к произвольному элементу из словаря

У меня есть словарь, полный предметов. Я хочу посмотреть на один, произвольный элемент:

print "Amongst our dictionary's items are such diverse elements as: %s" % arb(dictionary)

Мне все равно, какой предмет. Это не должно быть Случайных.

Я могу придумать много способов реализации этого, но все они кажутся расточительными. Мне интересно, если какие-либо предпочтительные идиомы в Python, или (даже лучше), если я пропущу один.

def arb(dictionary):
# Creates an entire list in memory. Could take a while.
    return list(dictionary.values())[0]

def arb(dictionary):
# Creates an entire interator. An improvement.
    for item in dictionary.itervalues():
        return item

def arb(dictionary):
# No iterator, but writes to the dictionary! Twice!
    key, value = dictionary.popitem()
    dictionary[key] = value
    return value

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

 the wolf15 мая 2012 г., 06:55
Должны ли они быть разными предметами во время разговора? Все это вернет один и тот же элемент ...
 Chris Morgan15 мая 2012 г., 09:29
Никакой дополнительной работы, когда вы знаете, что вам это не нужно, не является преждевременной оптимизацией. Это эффективность.
 jamylak15 мая 2012 г., 05:08
@ sgerg Я собирался представить это, но ты продолжаешь. : D
 srgerg15 мая 2012 г., 05:07
Как насчетdictionary.itervalues().next()? Это было бы лучше, чем ваш второйarb функция.
 moooeeeep15 мая 2012 г., 09:49
если хочешь заглянутьпредме (в отличие от значения) вы должны использоватьiteritems неitervalues / nitpick /

Ответы на вопрос(4)

что на этот вопрос был получен значительный ответ, но, надеюсь, это сравнение позволит пролить некоторый свет на чистый код и время компромисс

from timeit import timeit
from random import choice
A = {x:[y for y in range(100)] for x in range(1000)}
def test_pop():
    k, v= A.popitem()
    A[k] = v

def test_iter(): k = next(A.iterkeys())

def test_list(): k = choice(A.keys())

def test_insert(): A[0] = 0

if __name__ == '__main__':
    print('pop', timeit("test_pop()", setup="from __main__ import test_pop", number=10000))
    print('iter', timeit("test_iter()", setup="from __main__ import test_iter", number=10000))
    print('list', timeit("test_list()", setup="from __main__ import test_list", number=10000))
    print('insert', timeit("test_insert()", setup="from __main__ import test_insert", number=10000))

Вот результаты:

('pop', 0.0021750926971435547)
('iter', 0.002003908157348633)
('list', 0.047267913818359375)
('insert', 0.0010859966278076172)

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

Решение Вопроса

но, на мой взгляд, немного более очевидно:

return next(iter(dictionary.values()))

Это работает как в Python 2, так и в Python 3, но в Python 2 более эффективно сделать это следующим образом:

return next(dictionary.itervalues())
 Chris Morgan15 мая 2012 г., 09:35
@ Нечетное мышление: если тыявляютс просто хочу один элемент от итератора,next это путь. Нет смысла вfor a in b: return c или имеющий безусловныйbreak оператор в первой итерации цикла.
 yak15 мая 2012 г., 07:32
Следует отметить, что это вызывает StopIteration, если dict пуст.
 Oddthinking15 мая 2012 г., 09:25
Я не уверен, что вижу это как «гораздо более очевидное», но определенные моменты для подбора в одном выражении.
 Chris Morgan15 мая 2012 г., 09:21
Но если вы хотите избежатьStopIteration, вы можете указать значение по умолчанию, например,next(dictionary.itervalues(), None).
 Aran-Fey17 янв. 2018 г., 07:08
Я обновил ваш ответ для современного Python 3 раза, потому что это все еще популярный вопрос. Если вы недовольны внесенными мною изменениями, не стесняйтесь откатываться или редактировать по своему вкусу.

Избегая всегоvalues/itervalues/viewvalues беспорядок, это одинаково хорошо работает в Python2 или Python3

dictionary[next(iter(dictionary))]

Альтернативно, если вы предпочитаете выражения генератора

next(dictionary[x] for x in dictionary)
 Ev. Kounis17 мая 2017 г., 15:02
ты мог бы просто сделатьnext(iter(dictionary.values()))
 John La Rooy18 мая 2017 г., 01:28
@ Ev.Kounis, но в python2 это создает дополнительный список.
 John La Rooy18 мая 2017 г., 01:53
@ user2357112, ах да, ты прав. Я удалю это, поскольку некоторые люди все еще пытаются поддерживать 2 и
 user235711218 мая 2017 г., 01:51
map также создает список в Python 2.

Почему бы не использоватьrandom?

import random

def arb(dictionary):
    return random.choice(dictionary.values())

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

Жаль, что dict_values не поддерживает индексацию, было бы неплохо вместо этого передать представление значений.

Update: так как все так одержимы производительностью, приведенной выше функции требуется <120 мс, чтобы вернуть случайное значение из разряда в 1 миллион предметов. Доверие к чистому коду - это не удивительный удар по производительност

 Matthew Trevor15 мая 2012 г., 17:31
Если имя «произвольное» и действие состоит в том, чтобы перебирать ключи, это имя мне не будет понятно, поэтому да, необходима строка документации. Если вам нужно написать строку документации, чтобы объяснить, почему ваш код делает что-то другое, чем кажется, возможно, ответ - написать более четкий код.
 Chris Morgan15 мая 2012 г., 09:23
Где было указано, что выбранный элемент не должен быть случайным, это пустая трата времени. Строка документа (и имя!) Вполне достаточна для таких наблюдений.
 user235711218 мая 2017 г., 01:56
120 мс совершенно неприемлемо для такой операции. Это должно закончиться в течение микросекунды. Вы положили это туда, где вы ранее использовалиd[next(iter(d))] и ваше приложение может работать буквально в миллион раз медленнее.

Ваш ответ на вопрос