2016-11-19 3 views
0

python 3.5の値を遅延計算するためのコードを以下に示します。私は同じ結果で@cached_propertydecoratorを試したので、これを簡単にするために使用します。次からPythonで引数として渡す際の遅延プロパティの評価を回避する方法

def bar(some_parameter, another_parameter): 
    if some_parameter != 10: 
     print(some_parameter) 
    else: 
     print(another_parameter) 

:私はそれがこの例のように、終わるの内部に使用されていない場合でも、関数の引数として渡したときに

class Foo:  
    @property 
    def expensive_object(self): 
     if not hasattr(self, "_expensive_object"):    
      print("Lengthy initialization routine") 
      self._expensive_object = 2 
     return self._expensive_object   

問題は、それが評価されることをです出力されただけで評価されていることがわかりますが、コードがそれを使用しようとしていないため、厳密には必要ではありませんでした。

In [23]: foo1 = Foo() 
    ...: bar(3, foo1.expensive_object) 
     Lengthy initialization routine 
     3 

In [24]: bar(3, foo1.expensive_object) 
     3 

は私のスクリプトは、これまで評価しなくても実行することができている状況でありますが、それはので、このような場合の、とにかくそれをやってしまいます。 パラメータを除外することも現実的ではありません。私はまた、組み立てられたメンバオブジェクトの__init__でそれを使用します。

可能であれば、実際に読み取ったときに評価する必要があるという点で、プロパティをさらに怠惰にしたいと考えています。

+1

それはlazierにする唯一の方法は、それを作ることです'bar'が必要なときに呼び出す関数です。関数の引数は常にすぐに評価されます。 – chepner

答えて

4

Pythonには、シンプルで慣れないレイジープロパティ評価がありません。

怠惰なプロパティ評価を得るためのスキームはいくつかありますが、呼び出される関数(bar)の参加と協力が必要です。例えば。あなたは、オブジェクトとプロパティ名

def bar2(x, y, propname): 
    if x != 10: 
     print(x) 
    else: 
     print(getattr(y, propname)) 

bar2(3, foo1, 'expensive_object') 

それとも、ラムダのように呼び出し可能に渡すことで渡すことができます。

def bar3(x, y): 
    if x != 10: 
     print(x) 
    else: 
     print(y()) 

bar3(3, lambda: foo1.expensive_object) 

しかし、すべての洗練のために、Pythonのは、かなりシンプルな言語ですハート。 の最も単純なCコンパイラまたはJavaコンパイラでさえ、 でも日常的に行うことはほとんどありません。ほぼ形而上学的な左辺値/右辺値を維持しません Perlで見られる区別です(これは本当に役に立つでしょう)。 そして、プロパティの呼び出しを遅らせるために、 thunksを動的に挿入して評価しようとしません。 foo1.expensive_objectに電話すると、その値が計算され、 が渡されます。それを別の方法で行いたい場合は、 を上記のような他の重要な取り決めにする必要があります。

あなたが定期的に遅延/遅延評価を必要とするつもりなら、評価-IF-必要なヘルパー関数を定義するために便利なことができます:

def get_value(x): 
    return x() if hasattr(x, '__call__') else x 

必要なときに多少、Yを評価正則ことができますこの方法。使用した機能は、まだ協力しているが、これはあなたが望むときに、静的な値で渡すことができます、またはあなたが評価lazierを行う必要がありラムダ:

def bar4(x, y): 
    if x != 10: 
     print(x) 
    else: 
     print(get_value(y)) 

bar4(3, 33) # works 
bar4(4, lambda: foo1.expensive_object) # also works! 
+0

私は渡されたか、呼び出されたならば財産を差別化する方法を見つけることを望んでいましたが、今はそうではないと思いました。 ゲッター機能のために解決します。 これは素晴らしい例でした! – mvbentes

関連する問題