From: Neal Becker on
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


From: Simon Brunning on
On 10 March 2010 13:12, Neal Becker <ndbecker2(a)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.

--
Cheers,
Simon B.
From: Mark Lawrence on
Neal Becker 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
>
>
I think it's because X has already been constructed when __init__ is
called, so __new__ is the place for your conditional code.

From: Neal Becker on
Simon Brunning wrote:

> On 10 March 2010 13:12, Neal Becker <ndbecker2(a)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.

From: Matt Nordhoff on
Neal Becker wrote:
> Simon Brunning wrote:
>
>> On 10 March 2010 13:12, Neal Becker <ndbecker2(a)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