Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Can't define __call__ within __init__?

Reply
Thread Tools

Can't define __call__ within __init__?

 
 
Neal Becker
Guest
Posts: n/a
 
      03-10-2010
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


 
Reply With Quote
 
 
 
 
Steven D'Aprano
Guest
Posts: n/a
 
      03-11-2010
On Wed, 10 Mar 2010 08:12:14 -0500, 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



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
 
Reply With Quote
 
 
 
 
Neal Becker
Guest
Posts: n/a
 
      03-11-2010
Steven D'Aprano wrote:

> On Wed, 10 Mar 2010 08:12:14 -0500, 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

>
>
> 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.
>
>
>

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.

 
Reply With Quote
 
Steve Holden
Guest
Posts: n/a
 
      03-11-2010
Neal Becker wrote:
> Steven D'Aprano wrote:
>
>> On Wed, 10 Mar 2010 08:12:14 -0500, 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

>>
>> 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.
>>
>>
>>

> 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.

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/

 
Reply With Quote
 
Andre Engels
Guest
Posts: n/a
 
      03-11-2010
On Thu, Mar 11, 2010 at 2:30 PM, Steve Holden <(E-Mail Removed)> wrote:

>> 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, http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
MRAB
Guest
Posts: n/a
 
      03-11-2010
Andre Engels wrote:
> On Thu, Mar 11, 2010 at 2:30 PM, Steve Holden <(E-Mail Removed)> wrote:
>
>>> 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.
>

Addendum: a bad algorithm is bad, whatever language it's written in.
 
Reply With Quote
 
Steve Howell
Guest
Posts: n/a
 
      03-11-2010
On Mar 10, 7:18*pm, Steven D'Aprano
<(E-Mail Removed)> wrote:
> On Wed, 10 Mar 2010 08:12:14 -0500, 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

>
> 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.
>


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).
 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      03-11-2010
Steve Howell wrote:

> On Mar 10, 7:18 pm, Steven D'Aprano
> <(E-Mail Removed)> 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
 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      03-12-2010
On Thu, 11 Mar 2010 08:20:14 -0800, Steve Howell 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.


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
 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      03-12-2010
On Thu, 11 Mar 2010 07:56:59 -0500, Neal Becker wrote:

> 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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Can't define __call__ within __init__? Neal Becker Python 5 03-10-2010 11:38 PM
Redefining __call__ in an instance Robert Ferrell Python 5 01-21-2004 09:34 PM
RE: Redefining __call__ in an instance Robert Brewer Python 1 01-16-2004 02:58 AM
newbie question, when __call__ method is used? chenyu Python 1 10-27-2003 05:26 AM
Why doesn't __call__ lead to infinite recursion? Patrick Lioi Python 7 08-19-2003 06:41 PM



Advertisments