0

私は、他の人のコードを見る前に、メモ化デコレータの独自のバージョンを作成しようとして、徹底的に遊んでいます。正直なところ、それはもっと楽しい練習です。しかし、遊んでいるうちに、デコレータでやりたいことができないことがわかりました。

def addValue( func, val ):
    def add( x ):
        return func( x ) + val
    return add

@addValue( val=4 )
def computeSomething( x ):
    #function gets defined

私がそれをしたいなら、私はこれをしなければなりません:

def addTwo( func ):
    return addValue( func, 2 )

@addTwo
def computeSomething( x ):
    #function gets defined

このようにデコレータでキーワード引数を使用できないのはなぜですか? 私は何を間違っていますか、どうすればよいか教えてもらえますか?

4

3 に答える 3

5

関数を部分的に適用したい-引数addValueを与えますが、 . これを行うには、一般に次の 2 つの方法があります。valfunc

最初のものはカリー化と呼ばれ、interjay の回答で使用されます: 2 つの引数を持つ関数の代わりに、f(a,b) -> res2 番目の引数を取る別の関数を返す最初の引数の関数を記述します。g(a) -> (h(b) -> res)

もう一つの方法はfunctools.partialオブジェクトです。関数の検査を使用して、関数を実行する必要がある引数を特定します (この場合はfuncval )。パーシャルを作成するときに追加の引数を追加できます。パーシャルを呼び出すと、指定されたすべての追加の引数が使用されます。

from functools import partial
@partial(addValue, val=2 ) # you can call this addTwo
def computeSomething( x ): 
    return x

パーシャルは通常、このパーシャル アプリケーションの問題、特に引数が 2 つ以上の場合のはるかに簡単なソリューションです。

于 2010-06-13T15:08:05.197 に答える
5

デコレータを返す関数を定義する必要があります:

def addValue(val):
    def decorator(func):
        def add(x):
            return func(x) + val
        return add
    return decorator

と書く@addTwoと、 の値addTwoがそのままデコレータとして使われます。ただし、 を記述する@addValue(4)と、最初addValue(4)に addValue 関数を呼び出して評価されます。次に、結果がデコレータとして使用されます。

于 2010-06-13T14:39:44.150 に答える
3

あらゆる種類の引数 (名前付き/キーワードのもの、名前のないもの/位置のもの、またはそれぞれのいくつか) を持つデコレータ (本質的に、単に言及するのではなく、行で呼び出すもの)は、レベルのネストが必要です (デコレータが単一レベルのネストがあることに言及してください)。行で呼び出したい場合は、引数のないものでも同様です。これは、最も単純で、何もしない、二重にネストされたデコレータです。@name@

def double():
  def middling():
    def inner(f):
      return f
    return inner
  return middling

これを次のように使用します

@double()
def whatever ...

括弧に注意してください (この場合、必要な引数も必要もないため、空です): を呼び出し ていることを意味doubleします。middlingwhatever

「呼び出し」と「言及だけ」の違いがわかれば、名前付き引数 (オプションなど) を追加するのは難しくありません。

def doublet(foo=23):
  def middling():
    def inner(f):
      return f
    return inner
  return middling

次のいずれかとして使用できます。

@doublet()
def whatever ...

またはとして:

@doublet(foo=45)
def whatever ...

または同等に次のように:

@doublet(45)
def whatever ...
于 2010-06-13T15:15:28.700 に答える