Can't define __call__ within __init__?

Matt Nordhoff mnordhoff at mattnordhoff.com
Wed Mar 10 14:58:07 CET 2010


Neal Becker wrote:
> Simon Brunning wrote:
> 
>> On 10 March 2010 13:12, Neal Becker <ndbecker2 at 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



More information about the Python-list mailing list