2012-03-21 3 views
4

Как это можно сделать элегантно в питоне? Это называется ленивой оценкой или я смешиваю название с чем-то еще? Например:Избегайте или задерживайте оценку вещей, которые не могут быть использованы

>>> def foo(x): 
... print x 
... return x 
... 
>>> random.choice((foo('spam'), foo('eggs'))) 
spam 
eggs 
'eggs' 

Но нам не нужно было оценивать все эти предметы, или мы?

Это работает, но я считаю, что это будет очень некрасиво:

>>> random.choice((lambda: foo('spam'), lambda: foo('eggs')))() 
eggs 
'eggs' 

Другим примером может использовать dict.get(key, somedefault()) где somedefault действительно не нужно, чтобы называться, если key not in dict.

+3

Да, то, что вы описали, обычно известно как ленивая оценка. – adelphus

+1

Очевидным ответом здесь является простое использование функции '' foo() '' после выбора. Также, когда вы работаете с итераторами, не забудьте использовать генераторы над списками для ленивой оценки. –

ответ

5

Вы можете использовать partial (-ly применяется функция):

import random 
def foo(x): 
    print x 
    return x 

from functools import partial 
print random.choice((partial(foo,'spam'), partial(foo,'eggs')))() 

Когда вам нужно Dict с дефолтов вы можете использовать defaultdict

from collections import defaultdict 
d = defaultdict(somedefault) 
print d[k] # calls somedefault() when the key is missing 

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

1

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

>>> def foo(x): 
...  print x 
...  return x 
... 
>>> foo(random.choice(("spam", "eggs"))) 
spam 
'spam' 

Но вы можете создать вспомогательный класс, как это:

class LazyEval(object): 
    def __init__(self, func, *args, **kwargs): 
     self.func = func 
     self.args = args 
     self.kwargs = kwargs 

    def __call__(self): 
     return self.func(*self.args, **self.kwargs) 

random.choice((LazyEval(foo, "spam"), LazyEval(foo, "eggs")))() 
0

Просто сделать это ленивый:

random.choice((lambda: foo('spam'), lambda: foo('eggs')))() 
+0

К сожалению, стандартный 'dict.get (k, d)' не основан на механизме более высокого порядка. Вы можете написать свой собственный класс dict, хотя ;-) – Alfe

+0

Если вы обнаружите, что лямбда-синтаксис уродливый, пусть ваша функция foo() вернет соответствующую лямбду. Но быть ленивым (не отрываясь от того, что действительно нужно сделать) означает записать то, что должно быть сделано (в случае). Использование лямбда в точности таково: в нем говорится, что нужно делать, на всякий случай. Он не делает этого сразу. Это определение ленивого. – Alfe

7

Стандартный способ ленивой оценки в Python использует generators.

def foo(x): 
    print x 
    yield x 

random.choice((foo('spam'), foo('eggs'))).next() 

BTW. Python также позволяет generator expressions, поэтому ниже линии не будет ничего заранее рассчитать:

g = (10**x for x in xrange(100000000)) 
0

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

def foo(sequence): 
    def chooser(): 
     choice = random.choice(sequence) 
     print choice 
     return choice 
    return chooser 

>>> c = foo(['spam', 'eggs', 'ham']) 
>>> c() 
... ham 
>>> 'ham' 
Смежные вопросы