2012-03-21 7 views
4

この種のものは、どのようにしてエレガントな形でPythonで処理できますか?それは怠惰な評価と呼ばれるのですか、私は何か他のものと名前を混合していますか?例:使用できないものの評価を避けるか遅らせる

>>> 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' 

別の例はsomedefaultが本当にkey not in dictない限り、呼び出す必要はありませんでしたdict.get(key, somedefault())を使用している場合があります。

+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')))() 

あなたはデフォルト値を持つ辞書を必要とするときは、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

もしlambda-syntaxが醜いなら、foo()関数は適切なラムダを返すようにしてください。しかし、実際にやるべきことを落とさずに怠け者になることは、何をすべきかを書き留めることを意味します。ラムダを使用するのはまさにそのことです。それはすぐにそれをしません。それは怠け者の定義です。 – Alfe

7

Pythonで遅延評価を行う標準的な方法は、generatorsを使用しています。

def foo(x): 
    print x 
    yield x 

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

BTW。

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

別の解決策を構築し、あなたがランダムな選択に実行するアクションをカプセル化する呼び出し可能に返すことです。何かを事前に計算しないであろう線の下のように、Pythonはまた、generator expressionsことができます。

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

>>> c = foo(['spam', 'eggs', 'ham']) 
>>> c() 
... ham 
>>> 'ham' 
関連する問題