2012-01-22 30 views
5

Pythonは複雑な匿名関数をサポートしていません。良い選択肢は何ですか?例:python:匿名関数の代わりに

class Calculation: 
    def __init__(self, func): 
     self.func = func 

    def __call__(self, data): 
     try: 
     # check if the value has already been calculated 
     # if it has, it would be cached under key = self.func 
      return data[self.func] 
     except KeyError: 
      pass # first-time call; calculate and cache the values 
     data[self.func] = self.func(data) 
     return data[self.func] 

# with a simple function, which can be represented using lambda, this works great 
f1 = Calculation(lambda data : data['a'] * data['b']) 

# with a complicated function, I can do this: 
def f2_aux: 
    # some complicated calculation, which isn't suitable for a lambda one-liner 
f2 = Calculation(f2_aux) 

これは合理的な設計ですか?

もしそうなら、私がモジュールで定義する各f *のf * _auxの醜さを避ける方法はありますか?

UPDATE:使用の

例:

d = {'a' : 3, 'b' : 6} 

# computes 3 * 6 
# stores 18 in d under a key <function <lambda> at ...> 
# returns 18 
f1(d) 

# retrieves 18 from d[<function <lambda> at ...>] 
# returns 18, without having to recalculate it 
f1(d) 

がUPDATE:

ちょうど私の理解のために、私は内側の関数を使用したバージョンを追加しました。

def memoize(func): 
    def new_func(data): 
     try: 
     # check if the value has already been calculated 
     # if it has, it would be cached under key = self.func 
      return data[func] 
     except KeyError: 
      pass # first-time call; calculate and cache the values 
     data[func] = func(data) 
     return data[func] 
    return new_func 

@memoize 
def f1(data): 
    return data['a'] * data['b'] 
+5

いいえ、これは合理的な設計ではありません。あなたはmemoization(これは匿名関数とは無関係です)をしているように見えます。 'f1 = lambda a:expression'は常に' def f1(a):return expression'と全く同じです。 [これは勉強するための良いメモデコレータです](http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize)。ところで、 '@decorator def function:pass'は常に' def function:pass;と全く同じです。 function = decorator(function) ' –

+2

悪い点は、あなたのmemoizerが壊れていることです。結果キャッシュ 'data'はあなたの関数の引数でもあります... –

+0

@FrancisAvila:辞書要素' data [f] 'に' f(data) 'の値をキャッシュしようとしました。他の関数の値が別のキーの下にキャッシュされるため、他のものとの競合も起こらないはずです。それは(技術的に)うまくいくようです。不必要に混乱しているコードの問題ですか? – max

答えて

5

匿名の機能は必要ありません。また、メモ帳はこれよりもうまくいっています。おそらく自分のロールを出す理由はありません。

しかし、質問に答えるには:クラスをデコレータとして使用できます。

@Calculation 
def f2(): 
    ... 

これは、単に、関数を定義Calculationでそれをラップしf2ように、その結​​果を保存しました。 デコレータ構文が同等になるように定義されていますように、あなたの例の一つとしてクラスを書くに簡潔代替することができます

_decorator = Calculation # a fresh identifier 
# not needed here, but in other cases (think properties) it's useful 
def f2(): 
    ... 
f2 = _decorator(f2) 
+0

通常、デコレータはある関数を引数としてとり、別の関数を返す関数です - この場合、 'class Calculation'はそのコンストラクタシグネチャと' __call__'メソッドのためにこの役割に合っていますか? – max

+0

@max:デコレータには、呼び出し可能でなければならず、有用であることを除いて、何の制限もありません。これらは意味のある戻り値を持つ必要があります。クラスは '__new__' /' __init__'で呼び出すことができ、クラスのインスタンスは( '__call__'でも)呼び出し可能ですので、戻り値は便利です。 – delnan

+0

@max "呼び出し可能"、Pythonの言葉で。 –

1

閉鎖。この技術では、の定義をの内部に入れます。の定義はです。内部関数は、囲み関数内の変数にアクセスできます。 Python 3では、ローカルでないキーワードは、その変数への書き込みアクセス権を与えます。 Python 2では、非局所変数に変更可能な値を使用して、それを内部関数から更新できるようにする必要があります。無名関数に関する質問について

、言語は、意図的にが扱えるラムダよりも複雑な何のためDEFを使用するように戻ってあなたをプッシュします。

+0

私の質問に最後の更新で追加したようなものですか? – max

+0

はい、それはクロージャです。 –

4

匿名関数の代わりに非匿名関数があります。無名関数は、定義されているコンテキストでのみ匿名です。しかし、それは本当に匿名ではありません、あなたはそれを使用することができなかったからです。

Pythonでは、lambdaステートメントで匿名関数を作成します。あなたは、例えば、この操作を行うことができます。

output = mysort(input, lambda x: x.lastname) 

ラムダは、関数を作成しますが、その機能は、ローカル空間に名前がありませんし、自分自身のためにそれ自身の名前がちょうど'<lambda>'です。私たちはmysortを見ればしかし、それはこのような何かを定義する必要があります:

def mysort(input, getterfunc): 
    blahblahblah 

我々は機能がまったく匿名ではありません、この文脈では、ここで見るとおり。名前はgetterfuncです。この関数の観点からは、渡された関数が匿名であるかどうかは関係ありません。これは、同じようにうまく機能、およびすべての重要な点でまったく同じです:

def get_lastname(x): 
    return x.lastname 

output = mysort(input, get_lastname) 

確かに、それはより多くのコードを使用していますが、それは、より遅いか、そのようなものではありません。したがって、Pythonでは、無名関数は、通常の関数の文法上の砂糖にすぎません。

本当に匿名関数は

lambda x: x.lastname 

だろう。しかし、我々は何の結果の機能を割り当てないように、我々は関数の名前を得ることはありません、その後、我々はそれを使用することはできません。真に匿名の関数はすべて使用できません。

そのため、ラムダにはなれない関数が必要な場合は、通常の関数にしてください。意味のあるやり方で匿名にすることはできないので、なぜそれを匿名化するのはどうですか? Lambdaは、小さな1行の関数を必要とし、完全な関数を定義してスペースを無駄にしたくないときに便利です。彼らは匿名であることは無関係です。

+0

ありがとう..私は、書かれたコードの量(ひいては潜在的なタイプミスの数)を節約しようとしていたのではないかと思います。 – max