11

これを行う簡単な方法があるに違いありませんが、何とか頭を包み込むことができます。私が欲しいものを説明できる最良の方法は、クラスのラムダ関数です。動作するクラスのインスタンス化されていないバージョンを引数として期待するライブラリがあります。次に、作業するクラス自体をインスタンス化します。問題は、クラスのバージョンを動的に作成してライブラリに渡すことができるようにしたいのですが、ライブラリはインスタンス化されていないバージョンを想定しているため、その方法がわかりません。以下のコードは、問題を説明しています。

class Double:
    def run(self,x):
        return x*2

class Triple:
    def run(self,x):
        return x*3

class Multiply:
    def __init__(self,mult):
        self.mult = mult
    def run(self,x):
        return x*self.mult

class Library:
    def __init__(self,c):
        self.c = c()
    def Op(self,val):
        return self.c.run(val)

op1 = Double
op2 = Triple
#op3 = Multiply(5)

lib1 = Library(op1)
lib2 = Library(op2)
#lib3 = Library(op3)

print lib1.Op(2)
print lib2.Op(2)
#print lib3.Op(2)

最初にインスタンス化する必要があり、ライブラリ「AttributeError: Multiply インスタンスには呼び出しメソッドがありません」が壊れるため、汎用の Multiply クラスを使用できません。ライブラリクラスを変更せずに、これを行う方法はありますか?

4

6 に答える 6

12

ライブラリは、「初期化されていないバージョン」(つまり、クラス参照) が必要であることを本当に指定していますか?

私には、ライブラリが実際にオブジェクト ファクトリを必要としているかのように見えます。その場合、次のように入力できます。

lib3 = Library(lambda: Multiply(5))

ラムダの仕組みを理解するには、次の点を考慮してください。

Multiply5 = lambda: Multiply(5)
assert Multiply5().run(3) == Multiply(5).run(3)
于 2008-12-11T18:44:54.597 に答える
9

ラムダはまったく必要ありません。ラムダは、関数を定義して同時に使用するための単なるシンタックス シュガーです。ラムダ呼び出しを明示的な定義に置き換えることができるのと同じように、ニーズを満たす実際のクラスを作成して返すことで、問題を解決できます。

class Double:
        def run(self,x):
            return x*2

class Triple:
    def run(self,x):
        return x*3

def createMultiplier(n):
    class Multiply:
        def run(self,x):
            return x*n
    return Multiply

class Library:
    def __init__(self,c):
        self.c = c()
    def Op(self,val):
        return self.c.run(val)

op1 = Double
op2 = Triple
op3 = createMultiplier(5)

lib1 = Library(op1)
lib2 = Library(op2)
lib3 = Library(op3)

print lib1.Op(2)
print lib2.Op(2)
print lib3.Op(2)
于 2008-12-11T18:53:30.070 に答える
1

Library問題空間を正しく理解していれば、クラスを使用して呼び出される 1 つの引数を取る一般的なインターフェイスがあります。残念ながら、関数を呼び出すのではなくLibrary、関数がメソッドを持つクラスにラップされていることを前提としていますrun

これらのクラスは、プログラムで確実に作成できます。クラスはメソッドによって返される場合があり、クロージャーの概念のおかげで、ニーズを満たすクラスで任意の関数をラップできるはずです。何かのようなもの:

def make_op(f):
  class MyOp(object):
    def run(self, x):
      return f(x)
  return MyOp

op1 = make_op(lambda x: return x*2)
op2 = make_op(lambda x: return x*3)

def multiply_op(y):
    return make_op(lambda x: return x*y)

op3 = multiply_op(3)

lib1 = Library(op1)
lib2 = Library(op2)
lib3 = Library(op3)

print( lib1.Op(2) )
print( lib2.Op(2) )
print( lib3.Op(2) )

そうは言っても、関数を受け取るようにライブラリを変更してから関数を提供することは、おそらくこれを行うためのより強力な方法です。

于 2008-12-11T18:50:19.360 に答える
1

__call__これは一種の不正行為ですが、自分自身を返すメソッドをMultiply クラスに与えることができます:

class Multiply:
    def __init__(self,mult):
        self.mult = mult
    def __call__(self):
        return self
    def run(self,x):
        return x*self.mult

そうすれば、ライブラリがc()実際に呼び出すc.__call__()と、必要なオブジェクトが返されます。

于 2008-12-11T18:39:04.110 に答える
1
def mult(x):
    def f():
        return Multiply(x)
    return f


op3 = mult(5)
lib3 = Library(op3)
print lib3.Op(2)
于 2008-12-11T18:42:25.663 に答える
0

typeは Python クラス オブジェクトのデフォルト クラスであり、クラスを呼び出すとそのクラスの新しいインスタンスが作成されるためtype、正しい引数で呼び出すと新しいクラスが生成されます。

my_class = type("my_class", (object,), {"an_attribute": 1})

my_classは、値が 1 の「an_attribute」という属性を持つ、「my_class」という名前の新しいクラスを参照するようになりましたobject。メソッドは、関数オブジェクトを指す単なるクラス属性であるため、それらを辞書に追加できます。同様に属性の:

{"an_attribute": 1, "a_method": lambda self: print("Hello")}

これが仕組みです。絶対に必要でない限り、この方法はお勧めしません。すべてのケースの 99% では、そうではありません。目標を達成するためのクリーンな方法については、@Parker Coates の回答を参照してください。

于 2018-12-03T18:09:12.623 に答える