Redefining __call__ in an instance
Peter Otten
__peter__ at web.de
Fri Jan 16 04:59:54 EST 2004
Robert Ferrell wrote:
> I have a question about assigning __call__ to an instance to make that
> instance callable. I know there has been quite a bit of discussion
> about this, and I've read all I can find, but I'm still confused.
>
> I'd like to have a factory class that takes a string argument and returns
> the appropriate factory method based on that string. I'd like the
> instances to be callable. Like this:
>
> fact = Factory('SomeThing')
> aSomeThing = fact(some args)
>
> anotherFact = Factory('SomeThingElse')
> anotherThing = anotherFact(some other args)
I think fact and anotherFact could be methods instead of classes, e. g.
fact = Factory("SomeThing").someMethod # see complete example below
# Here's something that should meet your specs:
class Factory:
def __init__(self, times=1, *args):
self.times=times
def something(self, a1="alpha",*args):
print "something"
return a1*self.times
def somethingElse(self, a1="beta", *args):
print "something else"
return a1*self.times
def factory(what, *initargs):
""" factory with one instance per call """
return getattr(Factory(*initargs), what)
f1 = factory("something")
f2 = factory("somethingElse", 2)
for f in (f1, f2):
print "%s() --> %s" % (f.__name__, f())
> The way I thought to do this was to assign the __call__ attribute of
> the fact instance to the appropriate factory method in __init__. That
> does not
> work, as many others have pointed out. I know there are workarounds.
> The appended code shows the variants I know of. I can use one of
> them, but they are not quite what I am looking for.
>
> Have I missed the key message that explains how to make new-style
> classes callable, with the called method unique to each instance?
Why not be generous and make a dedicated (sub)class for each kind of call?
Every instance of a subclass of Callable is just a stateful function.
# Here's what I would prefer:
class Callable:
def __init__(self, times=1, *args):
self.times=times
class MoreCallable(Callable):
def __call__(self, a1="gamma",*args):
print "more"
return a1*self.times
class OrLessCallable(Callable):
def __call__(self, a1="delta",*args):
print "or less"
return a1*self.times
# a bare bones registry
_callables = {
"more": MoreCallable,
"less": OrLessCallable
}
def factory(what, *initargs):
# a variant that uses Callable instances
# instead of classes could easily be devised
return _callables[what](*initargs)
for f in (factory("more"), factory("less", 3)):
print "%s() --> %s" % (f.__class__.__name__, f())
Both variants respect default arguments.
Peter
More information about the Python-list
mailing list