2014-01-03 3 views
0

Я пытаюсь посмотреть, смогу ли я что-нибудь сфотографировать lazy в Python.Dict comprehension, кортежи и ленивая оценка

У меня есть определение dict, где значение является кортежем. Я хочу иметь возможность создать вторую запись кортежа, используя первую запись кортежа.

Примером может служить пример.

dictA = {'a': 1, 'b': 3, 'c': 42} 
{key: (a = someComplexFunction(value), moreComplexFunction(a)) for key, value in dictA.items()} 

Возможно ли, что moreComplexFunction использует вычисление в первой записи кортежа?

+0

У вас может быть 'someComplexFunction' реализовать [' lru_cache'] (http://docs.python.org/dev/library/functools.html#functools.lru_cache), тогда вы можете просто вызвать 'moreComplexFunction (someComplexFunction (значение)) 'и не получить удар производительности. Там * есть некоторые накладные расходы в кешировании, и это, вероятно, слишком велико, если вы используете кеш только один раз, поэтому я делаю это комментарием вместо ответа. – roippi

ответ

6

Вы можете добавить вторую петлю на один-элемент кортежа в:

{key: (a, moreComplexFuntion(a)) for key, value in dictA.items() 
           for a in (someComplexFunction(value),)} 

Это дает вам доступ к выходу someComplexFunction(value) в стоимостном выражении, но это довольно некрасиво.

Лично я бы перейти к регулярной петле в таких случаях:

dictB = {} 
for key, value in dictA.items(): 
    a = someComplexFunction(value) 
    dictB[key] = (a, moreComplexFunction(a)) 

и сделать с ней.

+0

Martijn, спасибо. Это кажется разумным, что нужно делать (по крайней мере, для меня). Очевидно, что для ясности петля лучше. Было бы неплохо иметь умную языковую функцию, которую я мог бы использовать для этого. :) – tchakravarty

+0

My +1 для обычного цикла. Код проще и эффективнее. – eryksun

+0

умная функция языка - это «лямбда-функции», которые являются частью инструментария функционального программирования и позволят вам вставлять эту функцию, т. Е. {Key: (lambda x: (x, moreComplexFunction (x))) (someComplexFunction (value)) для ключ, значение в dictA.items()}. но он уродливее, трудно читается и медленнее. петля легко читается и, вероятно, будет самой быстрой. –

2

или вы могли бы просто написать функцию, чтобы вернуть кортеж:

def kv_tuple(a): 
    tmp = someComplexFunction(a) 
    return (a, moreComplexFunction(tmp)) 

{key:kv_tuple(value) for key, value in dictA.items()} 

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

+0

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

+0

@fgnu: Создание функции * просто * для использования понимания болит эффективность и запутывает. Просто поместите цикл в функцию. – eryksun

+0

@eryksun - это может быть запутывающим, или это может быть проще. для меня сохранение сокращений делает их более легкими для меня читать (и, как я уже сказал, я бы предпочел использовать кортеж здесь). 'kv_tuple' не очень описательное имя, но я не знаю, для чего он используется ... может легко дать ему такое имя, что вышеприведенный оператор более четко генерирует данные X из данных Y в dictA (и которая будет еще проще читать).если нет веских оснований использовать 'kv_tuple' в другом месте кода, я согласен, я бы тоже пошел с петлей. –

1

Наряду с Martijn's answer, используя выражение генератора и понимание dict также является весьма семантическим и ленивым:

dictA = { ... } # Your original dict 

partially_computed = ((key, someComplexFunction(value)) 
         for key, value in dictA.items()) 

dictB = {key: (a, moreComplexFunction(a)) for key, a in partially_computed} 
+1

Это еще одна форма введения дополнительной петли :-) –

+0

@MartijnPieters Это именно то, что я думал! – tchakravarty

+0

Почему да, да, это>. <. Я думаю, что он вообще решает проблему «уродства». –

Смежные вопросы