1

私は、ローカルスコープでクラスのメソッドをデコレーション後の関数として公開したいと考えています。たとえば、私は、クラスとデコレータていた場合:Pythonでメソッドの関数バージョンを自動的に公開してデコレートする方法は?

def some_decorator(f): 
    ...transform f... 
    return decorated_f 

class C(object): 
    def __init__(self,x): 
     self.x = x 
    def f(self,y): 
     "Some doc string" 
     return self.x + y 
    def g(self,y,z): 
     "Some other doc string" 
     return self.x + y + z 

を、私は、プロセスをautomizing気にしなかった場合、私は私のモジュールに次の次のコードを追加することができます。効果に

@some_decorator 
def f(C_instance,x): 
    "Some doc string." 
    return C_instance.f(x) 

@some_decorator 
def g(C_instance,x,y): 
    "Some other doc string." 
    return C_instance.g(x,y)  

を次のことが真であると評価すること

c = C(0) 
f(c,1) == c.f(1) 

私はこれを自動的に実行したいと考えています。次のようなものがあります。

my_funs = expose_methods(MyClass) 
for funname, fun in my_funs.iteritems(): 
    locals()[funname] = some_decorator(fun) 

foo = MyClass(data) 
some_functionality(foo,*args) == foo.some_functionality(*args) 

(この方法ではローカル変数を宣言するのが少し間違っているとは思いますが)トリックを行います。メソッドの関連するすべての属性が関数バージョンに正しく変換されるように、これをどのようにして行うことができますか?私は何か提案を感謝します。

P.S.

私はクラスインスタンスのメソッドをデコレートできることを知っていますが、これは実際に私が後にしていることではありません。これは、(1)ファンクションのバージョン構文の優先順位(2)私のデコレータが、ファンクションを最適化された方法でオブジェクトのコレクションにマップするということです。メソッドをデコレートすることによってビヘイビア(2)を取得するには、コレクションクラスがコレクションセマンティクスに直交するオブジェクトから属性を継承する必要があります。

+0

'locals()'によって返された辞書を変更することは未定義です。私はなぜここで 'globals()'の代わりに 'locals()'を使用しているのだろうかと思います。私が理解する限り、関数はモジュールのグローバルスコープに移動することになっています。 –

答えて

2

バインドされていないメソッドを直接使用できますか?

obj.foo(arg)ObjClass.foo(obj, arg)

class MyClass(object): 
    def foo(self, arg): 
     ... 

obj = MyClass() 
print obj.foo(3) == MyClass.foo(obj, 3) # True 

と同等でもClass method differences in Python: bound, unbound and staticdocumentationを参照してください。

+0

ハハ、そうです。まあ、私はそれを知らなかったと思います。あるいは、おそらく私はその問題に深く関わったので、私は単純な解決法を理解していませんでした。ありがとう。 –

+0

@GabrielMitchell:Python 2.xを使用している場合、そのようなアンバインドされたメソッドの最初の引数は 'MyClass'型でなければならないことに注意してください。これは' MyClass'インスタンスのコレクションを渡すのを妨げる可能性があります。 (ただし、この動作を変更する魔法のデコレータを定義することはできます) –

+0

@SvenMarnachええ、私は2.7です。私のデコレータの1人がargsを解析して、実際に何が呼び出されるかを決定する一環として、関連するコレクションのインスタンスを見つけます。これを避けるための3.xに関する特別なことはありますか? –

0

あなたは関数の構文を優先していると言います。クラスの外にあるすべてのメソッドを定義するだけで、希望どおりに動作させることができます。

class C(object): 
    def __init__(self,x): 
     self.x = x 

def f(c,y): 
    "Some doc string" 
    return c.x + y 
def g(c,y,z): 
    "Some other doc string" 
    return c.x + y + z 

あなたにもクラスにそれらをしたい場合は、いつでも行うことができます

for func in f, g: 
    setattr(C, func.__name__, func) 

またはその代わりに、関数名のイントロスペクションの地元のイントロスペクションを持つ:

for name in 'f', 'g': 
    setattr(C, name, locals()[name]) 

またはNOイントロスペクションとは、あなたがこれらのメソッド/関数をかなりたくさん持っていない限り、おそらくもっと簡単で簡単に管理できます:

C.f = f 
C.g = g 

これはまた、アンバインドされたメソッドの最初の引数がクラスのインスタンスであることをPythonがチェックしていることに対するcodeapeの答えについてのコメントに記載されている潜在的な問題を回避します。

関連する問題