[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Can't define __call__ within __init__?

Neal Becker

3/10/2010 1:12:00 PM

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


9 Answers

Steven D'Aprano

3/11/2010 3:19:00 AM

0

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

Neal Becker

3/11/2010 12:57:00 PM

0

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.

Steve Holden

3/11/2010 1:30:00 PM

0

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://pyco...
Holden Web LLC http://www.hold...
UPCOMING EVENTS: http://holdenweb.event...

Andre Engels

3/11/2010 2:15:00 PM

0

On Thu, Mar 11, 2010 at 2:30 PM, Steve Holden <steve@holdenweb.com> 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, andreengels@gmail.com

MRAB

3/11/2010 4:02:00 PM

0

Andre Engels wrote:
> On Thu, Mar 11, 2010 at 2:30 PM, Steve Holden <steve@holdenweb.com> 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.

Steve Howell

3/11/2010 4:20:00 PM

0

On Mar 10, 7:18 pm, Steven D'Aprano
<ste...@REMOVE.THIS.cybersource.com.au> 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/data...

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

Peter Otten

3/11/2010 4:36:00 PM

0

Steve Howell wrote:

> 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

Steven D'Aprano

3/12/2010 3:25:00 AM

0

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

Steven D'Aprano

3/12/2010 3:30:00 AM

0

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