Can't define __call__ within __init__?

Discussion in 'Python' started by Neal Becker, Mar 10, 2010.

  1. Neal Becker

    Neal Becker Guest

    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
     
    Neal Becker, Mar 10, 2010
    #1
    1. Advertising

  2. 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
     
    Steven D'Aprano, Mar 11, 2010
    #2
    1. Advertising

  3. Neal Becker

    Neal Becker Guest

    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.
     
    Neal Becker, Mar 11, 2010
    #3
  4. Neal Becker

    Steve Holden Guest

    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/
     
    Steve Holden, Mar 11, 2010
    #4
  5. Neal Becker

    Andre Engels Guest

    On Thu, Mar 11, 2010 at 2:30 PM, Steve Holden <> 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,
     
    Andre Engels, Mar 11, 2010
    #5
  6. Neal Becker

    MRAB Guest

    Andre Engels wrote:
    > On Thu, Mar 11, 2010 at 2:30 PM, Steve Holden <> 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.
     
    MRAB, Mar 11, 2010
    #6
  7. Neal Becker

    Steve Howell Guest

    On Mar 10, 7:18 pm, 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.
    >


    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).
     
    Steve Howell, Mar 11, 2010
    #7
  8. Neal Becker

    Peter Otten Guest

    Steve Howell wrote:

    > On Mar 10, 7:18 pm, Steven D'Aprano
    > <> 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
     
    Peter Otten, Mar 11, 2010
    #8
  9. 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, Mar 12, 2010
    #9
  10. 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
     
    Steven D'Aprano, Mar 12, 2010
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Steven Bethard
    Replies:
    2
    Views:
    471
    Steven Bethard
    Feb 16, 2005
  2. Kent Johnson
    Replies:
    7
    Views:
    931
    Jan Niklas Fingerle
    Feb 12, 2006
  3. Neal Becker
    Replies:
    5
    Views:
    273
    Neal Becker
    Mar 10, 2010
  4. Ramchandra Apte
    Replies:
    17
    Views:
    355
    Manuel Pégourié-Gonnard
    Sep 30, 2012
  5. Marco
    Replies:
    1
    Views:
    190
    Ian Kelly
    Nov 20, 2012
Loading...

Share This Page