class X (object):
def __init__(self, i):
if i == 0:
def __call__ (self):
return 0
else:
def __call_ (self):
return 1
x = X(0)
x()
TypeError: 'X' object is not callable
__call__ is in the __init__ method's local namespace - you need to
bind it to the class's namespace instead:
X.__call__ = __call__
But this probably isn't what you want either, since all instances of X
will share the same method.
What are you trying to do? In your simple example, you'd be much
better off with a single __call__ method. But you knew that.
--
Cheers,
Simon B.
> On 10 March 2010 13:12, Neal Becker <ndbe...@gmail.com> wrote:
>> Want to switch __call__ behavior. Why doesn't this work? What is the
>> correct way to write this?
>>
>> class X (object):
>> def __init__(self, i):
>> if i == 0:
>> def __call__ (self):
>> return 0
>> else:
>> def __call_ (self):
>> return 1
>>
>>
>> x = X(0)
>>
>> x()
>> TypeError: 'X' object is not callable
>
> __call__ is in the __init__ method's local namespace - you need to
> bind it to the class's namespace instead:
>
> X.__call__ = __call__
>
> But this probably isn't what you want either, since all instances of X
> will share the same method.
>
> What are you trying to do? In your simple example, you'd be much
> better off with a single __call__ method. But you knew that.
>
Sorry, a bit early in the morning. This works:
class X (object):
def __init__(self, i):
if i == 0:
def F (self):
return 0
else:
def F (self):
return 1
self.F = F
def __call__ (self):
return self.F (self)
Not sure if there is a more elegant (or compact) way to write this.
Could __call__ be defined directly within __init__?
What I'm trying to do is make a callable whose behavior is switched based on
some criteria that will be fixed for all calls. In my example, this will
ultimately be determined by the setting of a command line switch.
ISTM it would be prettiest to do:
class X(object):
def __init__(self, i):
self.flag = i == 0
def __call__(self):
if self.flag:
return 0
else:
return 1
Or, if the comparison isn't particularly expensive, it would look nicer
to just use self.i and do "self.i == 0" in __call__.
Not that it matters, but this is probably faster than your version, too,
since it saves a method call.
By the way, IIRC Python only looks up double-underscore methods on the
class, not the instance. That's why you had to indirect through self.F.
--
Matt Nordhoff
> What I'm trying to do is make a callable whose behavior is switched
> based on some criteria that will be fixed for all calls. In my
> example, this will ultimately be determined by the setting of a
> command line switch.
>
If you want different behaviour its usually best to use different classes.
You can keep all the common behaviour in a base class and just override the
__call__ method for the different behaviour. Then use a factory function to
decide which class to instantiate or else override __new__ and make the
decision there. e.g.
>>> class X(object):
def __call__(self):
return 0
def __new__(cls, i):
if i!=0:
cls = Y
return object.__new__(cls)
>>> class Y(X):
def __call__(self):
return 1
>>> x = X(0)
>>> x()
0
>>> y = X(1)
>>> y()
1
>>> isinstance(x, X)
True
>>> isinstance(y, X)
True
P.S. I don't know what you did in your post but your Followup-To header is
pointing to a group on gmane which makes extra work for me replying. Please
don't do that.
I'm sorry about that, there is some bad interaction between gmane's nntp-
smtp gateway and python's mail list. I don't know what to do about it. I
think the problem only happens on python's mail list (I've never seen it
reported on any of the MANY other lists I use via gmane).
Are the other mailing lists gatewayed from Usenet? It may not matter if
there's a followup-to header on a mailing list, it probably just gets
ignored, but it does matter on Usenet (which after all is what Gmane is
emulating).
For the record, it isn't really gatewayed to usenet - it's just allowing you
to read your favorite ML via nntp - which is MUCH more sensible than
actually having all that mail delivered personally to you, if you read a lot
of lists.
python-list is also gatewayed to the real USENET group comp.lang.python in
addition to its GMane gateway. Duncan is reading comp.lang.python from a real
USENET server, not via python-list through his email client. Most of the other
lists you read via GMane aren't gatewayed to the real USENET, so your
Followup-To header never caused a problem for anyone else.
--
Robert Kern
"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
I think it may be your news reader adding the Original-Followup-To header. I use
Thunderbird 3 to read this list via GMane, too, but my posts do not contain the
header. What newsreader are you using?
> On 2010-03-10 12:23 PM, Neal Becker wrote:
>> Duncan Booth wrote:
>> ...
>>>
>>> P.S. I don't know what you did in your post but your Followup-To header
>>> is pointing to a group on gmane which makes extra work for me replying.
>>> Please don't do that.
>>
>> I'm sorry about that, there is some bad interaction between gmane's nntp-
>> smtp gateway and python's mail list. I don't know what to do about it.
>> I think the problem only happens on python's mail list (I've never seen
>> it reported on any of the MANY other lists I use via gmane).
>
> I think it may be your news reader adding the Original-Followup-To header.
> I use Thunderbird 3 to read this list via GMane, too, but my posts do not
> contain the header. What newsreader are you using?
>
knode.
> Want to switch __call__ behavior. Why doesn't this work? What is the
> correct way to write this?
>
> class X (object):
> def __init__(self, i):
> if i == 0:
> def __call__ (self):
> return 0
> else:
> def __call_ (self):
> return 1
Others have already pointed out that there are two reasons that won't
work:
(1) you define __call__ as a local variable of the __init__ method which
then disappears as soon as the __init__ method completes; and
(2) special methods like __call__ are only called on the class, not the
instance, so you can't give each instance its own method.
Perhaps the best way to solve this is to use delegation:
def zero_returner():
return 0
def one_returner():
return 1
class X (object):
def __init__(self, i):
if i == 0:
self.func = zero_returner
else:
self.func = one_returner
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
zero_returner and one_returner can be any callable object, not
necessarily a function.
Of course, all this assumes that your solution isn't even simpler:
class X (object):
def __init__(self, i):
self.i = i
def __call__(self):
return self.i
but I assume if it was that simple, you would have done that already.
--
Steven
The example I showed was just a toy problem. The real problem is
I expect to call a function many times, and I want to avoid the overhead of
the 'if blah' everytime.
regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
See PyCon Talks from Atlanta 2010 http://pycon.blip.tv/
Holden Web LLC http://www.holdenweb.com/
UPCOMING EVENTS: http://holdenweb.eventbrite.com/
>> The example I showed was just a toy problem. The real problem is
>> I expect to call a function many times, and I want to avoid the overhead of
>> the 'if blah' everytime.
>>
> This is a premature optimization. First, make it work. Then (if it
> doesn't work fast enough) make it work faster.
Corrolary: When you do make it faster, make it faster where it is slow.
Second corrolary: If making it fast is so important that these two
rules do not apply, Python is not your language of choice.
--
André Engels, andre...@gmail.com
Are you sure about that? This program prints 1, 2, 1, 2.
class Foo:
def __init__(self, a):
if a == 1:
self.__call__ = lambda: 1
else:
self.__call__ = lambda: 2
foo1 = Foo(1)
print foo1()
foo2 = Foo(2)
print foo2()
print foo1()
print foo2()
See here:
http://docs.python.org/reference/datamodel.html
Class instances
Class instances are described below. Class instances are callable
only when the class has a __call__() method; x(arguments) is a
shorthand for x.__call__(arguments).
> On Mar 10, 7:18 pm, Steven D'Aprano
> <ste...@REMOVE.THIS.cybersource.com.au> wrote:
>> (2) special methods like __call__ are only called on the class, not the
>> instance, so you can't give each instance its own method.
> Are you sure about that? This program prints 1, 2, 1, 2.
You are using a classic class while the behaviour described above applies to
newstyle classes:
>>> class Foo:
... def __init__(self):
... self.__call__ = lambda: 42
...
>>> Foo()()
42
>>> class Bar(object):
... def __init__(self):
... self.__call__ = lambda: 42
...
>>> Bar()()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'Bar' object is not callable
I don't think it's a good idea to write new code that requires a classic
class.
Peter
>> (2) special methods like __call__ are only called on the class, not the
>> instance, so you can't give each instance its own method.
>>
>>
> Are you sure about that? This program prints 1, 2, 1, 2.
The rules for classic classes are different. Since classic classes have
gone away in 3.0, and are becoming rarer in 2.x, I didn't bother to
mention the complication.
--
Steven
> The example I showed was just a toy problem. The real problem is I
> expect to call a function many times, and I want to avoid the overhead
> of the 'if blah' everytime.
Unless the __call__ methods are very small, the overhead of one extra if
and one extra attribute lookup will be insignificant.
--
Steven