There must be an easy way to do this, but somehow I can wrap my head around it. The best way I can describe what I want is a lambda function for a class. I have a library that expects as an argument an uninstantiated version of a class to work with. It then instantiates the class itself to work on. The problem is that I'd like to be able to dynamically create versions of the class, to pass to the library, but I can't figure out how to do it since the library expects an uninstantiated version. The code below describes the problem:
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)
I can't use the generic Multiply class, because I must instantiate it first which breaks the library "AttributeError: Multiply instance has no call method". Without changing the Library class, is there a way I can do this?
-
This is sort of cheating, but you could give your Multiply class a
__call__method that returns itself:class Multiply: def __init__(self,mult): self.mult = mult def __call__(self): return self def run(self,x): return x*self.multThat way when the library calls
c()it actually callsc.__call__()which returns the object you want. -
def mult(x): def f(): return Multiply(x) return f op3 = mult(5) lib3 = Library(op3) print lib3.Op(2) -
Does the library really specify that it wants an "uninitialized version" (i.e. a class reference)?
It looks to me as if the library actually wants an object factory. In that case, it's acceptable to type:
lib3 = Library(lambda: Multiply(5))To understand how the lambda works, consider the following:
Multiply5 = lambda: Multiply(5) assert Multiply5().run(3) == Multiply(5).run(3) -
If I understand your problem space correctly, you have a general interface that takes 1 argument which is called using the
Libraryclass. Unfortunately, rather than calling a function,Libraryassumes that the function is wrapped in a class with arunmethod.You can certainly create these classes programatically. Classes may be returned by methods, and thanks to the concept of closures you should be able to wrap any function in a Class that meets your needs. Something like:
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) )That being said, changing Library to take a function and then providing functions is probably the stronger way to do this.
-
There's no need for lambda at all. lambda is just syntatic sugar to define a function and use it at the same time. Just like any lambda call can be replaced with an explicit def, we can solve your problem by creating a real class that meets your needs and returning it.
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)Greg Case : The advantage of using a general converter, of course, is that it would accept in principle any one-arg function, freeing further implementations from needing to explicitly define their ClassesDeestan : I like the createMultiplier() function. Elegant.MTsoul : I know this is an old post, but here is something worth noting. createMultiplier(4) != createMultiplier(4). This is because the class is created twice in two different memory locations. Unless Multiply has a metaclass that overrides the default behaviour for comparing classes, you should create a simple dictionary to cache the produced class objects. The dict would be keyed by n, and the values would be the classes. But this may not be memory efficient if a bunch of classes are created but unused. Simpliest way here is to attach a class attribute to Multiply. E.g. Multiply.x = 5.
0 comments:
Post a Comment