2012-01-26 11 views
3

私はpartialのようなものを再実装しようとしました(後でより多くの動作があります)。次の例では、lazycall1lazycall2と同じくらいうまく動作しているようですので、私はdocumentation of partialが長い第2バージョンを使用している理由を理解できません。助言がありますか?それは私を困らせることができますか?Pythonのクロージャと関数の属性

def lazycall1(func, *args, **kwargs): 
    def f(): 
     func(*args, **kwargs) 
    return f 

def lazycall2(func, *args, **kwargs): 
    def f(): 
     func(*args, **kwargs) 
    f.func=func # why do I need that? 
    f.args=args 
    f.kwargs=kwargs 
    return f 

def A(x): 
    print("A", x) 

def B(x): 
    print("B", x) 

a1=lazycall1(A, 1) 
b1=lazycall1(B, 2) 
a1() 
b1() 

a2=lazycall2(A, 3) 
b2=lazycall2(B, 4) 
a2() 
b2() 

編集:実際にはこれまでの回答はあまり正しくありません。二重引数でもうまくいくでしょう。別の理由はありますか?

def lazycall(func, *args): 
    def f(*args2): 
     return func(*(args+args2)) 
    return f 

def sum_up(a, b): 
    return a+b 

plusone=lazycall(sum_up, 1) 
plustwo=lazycall(sum_up, 2) 
print(plusone(6)) #7 
print(plustwo(9)) #11 

答えて

2

2番目のフォームにある唯一の余分なものは、いくつかの追加のプロパティです。これは、受信関数がこれらの値に基づいて決定を下すことができるように、lazycall2によって返された関数の回り込みを開始する場合に役立ちます。

0

functools.partialは、内部で返された関数で追加の引数またはオーバーライドされた引数を受け入れることができます。あなたの内部のf()関数はありません。だから、lazycall2でやっていることは必要ありません。しかし、あなたがこのようなことをしたい場合:

def sum(a, b): 
    return a+b 
plusone = lazycall3(sum, 1) 
plusone(6) # 7 

これらのドキュメントに示されていることを行う必要があります。

+0

これは違いはありません。私はより一般的な例で私の質問を編集しました。あれは正しいですか? – Gerenuk

+0

'functools.partial'によって返されるオブジェクトは、' .func'、 '.keywords'および' .func'属性を持ちます。ドキュメントは純粋なpythonでそれをエミュレートする方法を示しています。しかし、いいえ、返されたオブジェクトの*呼び出し*には影響しません。返されたオブジェクトで最初に渡された関数とargsにアクセスできるようにします。 – AdamKG

+0

OK、そうです。もちろんそうです。 – Gerenuk

0

はあなたにリンクするPythonドキュメントのページで、内部機能newfuncで引数名をよく見て、彼らは、argsfargskeywordsfkeywords内部関数に渡されたものとは異なっています。 partialを実装すると、外部関数が与えられたという引数が保存され、内部関数に与えられた引数に追加されます。

内部関数に同じ引数名を再利用するため、外部関数の元の引数はそこではアクセスできません。

外部関数の属性をfunc,argskwargsに設定すると、関数はPythonのオブジェクトであり、その属性を設定することができます。これらの属性を使用すると、元の関数と引数を関数lazycallに渡した後に元の関数と引数にアクセスできるようになります。従ってa1.funcAになり、a1.args[1]になります。

元の関数と引数を追跡する必要がない場合は、とlazycall1を使用してください。