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

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

print "Amongst our dictionary 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, поэтому, если есть понимал вариант, было бы неплохо принять его.

Ответ 1

Аналогично вашему второму решению, но немного более очевидному, на мой взгляд:

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

Это работает как в python 2, так и в python 3, но в python 2 более эффективно это делать:

return next(dictionary.itervalues())

Ответ 2

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

dictionary[next(iter(dictionary))]

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

next(dictionary[x] for x in dictionary)

Ответ 3

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

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 раз быстрее, чем создание списка и выбор из него случайного объекта.

Ответ 4

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

import random

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

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

Позор, который dict_values ​​не поддерживает индексирование, было бы неплохо, если бы вы могли перейти в представление значения.

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