473,372 Members | 1,017 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,372 software developers and data experts.

Redefining __call__ in an instance

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)

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?

thanks,
-robert

"""Test use of __call__ in a (new style) class.
The classes below show various ways of making instances
of a class callable. The goal is to make an instance callable,
with the called method defined distincly for each instance.
"""
def firstFunc(word = 'up'):
"""This is the method to call, when an instance is invoked."""
print "This is firstFunc, word %s." % word
return

class callWorks(object):
"""This works, since the called method is defined in the class."""
def __init__(self):
pass
def __call__(self, word = 'up'):
print 'This is inside callWorks, word %s.' % word
return

class callNoWork(object):
"""This doesn't work, since __call__ is defined for the method,
not the class."""
def __init__(self):
# This does not make an instance of callNoWork callable
self.__call__ = firstFunc

class callWorksNoFun(object):
"""This works, but since the class's method is being called, the
default arguments are defined by the class, and do not
properly reflect the default arguments of the method that
wants to be called."""
def __init__(self):
self._callFunc = firstFunc
def __call__(self, word = None):
# Although an instance of callWorksNoFun is callable,
# the default arguments are wrong
self._callFunc(word)
return

class addCallAttribute(object):
"""Add the attribute 'callMe', which is the callable function.
This works fine, but requires the user to invoke this as
instance.callMe(), rather than just instance()."""
def __init__(self):
self.callMe = firstFunc

# Simplest thing
cw = callWorks()
cw()

# Natural thing to try, but doesn't work
cnw = callNoWork()
# The instance, cnw, is not callable.
try:
cnw()
except Exception, exception:
print 'Call did not work, gave exception: %s.' % exception

# Works, but actually invoking class method, not instance's method
cwNF = callWorksNoFun()
# The instance cwNF is callable, but the default value for the callable is wrong.
# This works fine
cwNF('No up')
# This should default to print 'Up', but instead it defaults to None.
cwNF()

# Fine, but requires user to invoke instance.callMe(), rather than just instance().
aCA = addCallAttribute()
# To call the instance, use the callMe attribute. That respects defaults fine.
aCA.callMe()
Jul 18 '05 #1
5 2351
def firstFunc (s, word='up'):
print "foo"

class callNoWork(object):
def __new__ (cls):
cls.__call__ = firstFunc
return object.__new__(cls)

callNoWork()()

# Dunno if you've read this, but it explains this:
# http://python.org/2.2.1/descrintro.html

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)

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?

thanks,
-robert

"""Test use of __call__ in a (new style) class.
The classes below show various ways of making instances
of a class callable. The goal is to make an instance callable,
with the called method defined distincly for each instance.
"""
def firstFunc(word = 'up'):
"""This is the method to call, when an instance is invoked."""
print "This is firstFunc, word %s." % word
return

class callWorks(object):
"""This works, since the called method is defined in the class."""
def __init__(self):
pass
def __call__(self, word = 'up'):
print 'This is inside callWorks, word %s.' % word
return

class callNoWork(object):
"""This doesn't work, since __call__ is defined for the method,
not the class."""
def __init__(self):
# This does not make an instance of callNoWork callable
self.__call__ = firstFunc

class callWorksNoFun(object):
"""This works, but since the class's method is being called, the
default arguments are defined by the class, and do not
properly reflect the default arguments of the method that
wants to be called."""
def __init__(self):
self._callFunc = firstFunc
def __call__(self, word = None):
# Although an instance of callWorksNoFun is callable,
# the default arguments are wrong
self._callFunc(word)
return

class addCallAttribute(object):
"""Add the attribute 'callMe', which is the callable function.
This works fine, but requires the user to invoke this as
instance.callMe(), rather than just instance()."""
def __init__(self):
self.callMe = firstFunc

# Simplest thing
cw = callWorks()
cw()

# Natural thing to try, but doesn't work
cnw = callNoWork()
# The instance, cnw, is not callable.
try:
cnw()
except Exception, exception:
print 'Call did not work, gave exception: %s.' % exception

# Works, but actually invoking class method, not instance's method
cwNF = callWorksNoFun()
# The instance cwNF is callable, but the default value for the callable is wrong.
# This works fine
cwNF('No up')
# This should default to print 'Up', but instead it defaults to None.
cwNF()

# Fine, but requires user to invoke instance.callMe(), rather than just instance().
aCA = addCallAttribute()
# To call the instance, use the callMe attribute. That respects defaults fine.
aCA.callMe()


--
(------------------------------(
)~~~~~ Jason A. Mobarak ~~~~~~~)
(~~ aether_at_gentoo_dot_org ~~(
)~~~~ jmob_at_unm_dot_edu ~~~~~)
(------------------------------(
Jul 18 '05 #2

"Robert Ferrell" <fe*****@diablotech.com> wrote in message
news:73**************************@posting.google.c om...
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)

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?
Basically, the system does not look in the instance for the __call__
method for new style classes. I'm not sure why not, or where this
is defined, but that's the way it works.

To get a different callable for each instance, you need to do something
like this:

class fubar(object):
def __init__(self, callable):
self.myfunc = callable

def __call__(self, *a, **b):
self.myfunc(*a, **b)

thanks,
-robert

Jul 18 '05 #3
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

Jul 18 '05 #4
Jason Mobarak <jmob@nospam__unm.edu> wrote in message news:<x7********************@comcast.com>...
def firstFunc (s, word='up'):
print "foo"

class callNoWork(object):
def __new__ (cls):
cls.__call__ = firstFunc
return object.__new__(cls)

callNoWork()()

# Dunno if you've read this, but it explains this:
# http://python.org/2.2.1/descrintro.html


Thanks for the pointer. I had read this a while ago, it didn't all
sink in, and I'd forgotten about it. That was exactly the info that I
needed. In particular, it says that __call__ is a static method, so
it is not possible to define that differently for each instance.

The code above was a good reminder for me, but because __call__ is a
static method, any new instantiation redefines __call__ for all
existing instances.

Thanks for the pointer,
-robert
Jul 18 '05 #5

"Robert Ferrell" <fe*****@diablotech.com> wrote in message
news:73**************************@posting.google.c om...
Jason Mobarak <jmob@nospam__unm.edu> wrote in message news:<x7********************@comcast.com>...
def firstFunc (s, word='up'):
print "foo"

class callNoWork(object):
def __new__ (cls):
cls.__call__ = firstFunc
return object.__new__(cls)

callNoWork()()

# Dunno if you've read this, but it explains this:
# http://python.org/2.2.1/descrintro.html


Thanks for the pointer. I had read this a while ago, it didn't all
sink in, and I'd forgotten about it. That was exactly the info that I
needed. In particular, it says that __call__ is a static method, so
it is not possible to define that differently for each instance.

The code above was a good reminder for me, but because __call__ is a
static method, any new instantiation redefines __call__ for all
existing instances.


Huh, what? __call__() is *not* a static method. It's a perfectly
ordinary instance method, and there is nothing in the document
above that says anything different.

What it is is a static *attribute.* That's a different animal
entirely. Static attributes cannot be overridden by defining
them in an instance.

The entire issue is that old style and new style classes
treat a __call__ method in an instance differently. New style
classes ignore it, old style classes use it.

John Roth

Thanks for the pointer,
-robert

Jul 18 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Patrick Lioi | last post by:
def foo(): pass foo is a function foo is a callable object foo has method __call__ defined foo.__call__ is a function foo.__call__ is a callable object foo.__call__ has method __call__...
11
by: Stefan Behnel | last post by:
Hi! This somewhat puzzles me: Python 2.4 (#1, Feb 3 2005, 16:47:05) on linux2 Type "help", "copyright", "credits" or "license" for more information. ..>>> class test(object): .... def...
6
by: TK | last post by:
Hi, how can handle __call__? Can you give a sample? Thanks o-o Thomas
8
by: Rahul | last post by:
Consider the following: def a(x): return x+1 def b(f): def g(*args,**kwargs): for arg in args: print arg return f(*args,**kwargs) return g
2
by: Ksenia Marasanova | last post by:
Hi all, I am creating some library, and want use "declarative" style in the subclasses as much as possible, while the actual use will be more method-like. Just to give an impression, the...
5
by: Kent Johnson | last post by:
I am learning about metaclasses and there is something that confuses me. I understand that if I define a __call__ method for a class, then instances of the class become callable using function...
17
by: skip | last post by:
I don't personally use __call__ methods in my classes, but I have encountered it every now and then here at work in code written by other people. The other day I replaced __call__ with a more...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.