Избегайте или задерживайте оценку вещей, которые нельзя использовать - PullRequest
4 голосов
/ 21 марта 2012

Как ленивая оценка может быть достигнута в Python?Пара простых примеров:

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

Выше нам не нужно было оценивать все элементы этого кортежа, чтобы выбрать один.И ниже, значение по умолчанию foo() действительно не нужно вычислять, если только ключ поиска на самом деле не пропущен в dict:

>>> d = {1: "one"}
>>> d.get(2, foo("default"))
default
'default'
>>> d.get(1, foo("default"))
default
'one'

Я ищу Pythonic способ рефакторинга примеров, подобных приведенному вышеоценивать лениво.

Ответы [ 4 ]

7 голосов
/ 21 марта 2012

Стандартный способ выполнения ленивых вычислений в Python - использование генераторов .

def foo(x):
    print x
    yield x

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

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

g = (10**x for x in xrange(100000000))
5 голосов
/ 21 марта 2012

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

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

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

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

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

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

1 голос
/ 21 марта 2012

Если вы не приведете более реалистичный пример, я бы сделал это так:

>>> 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 голосов
/ 21 марта 2012

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

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

>>> c = foo(['spam', 'eggs', 'ham'])
>>> c()
... ham
>>> 'ham'
...