strange __call__

Discussion in 'Python' started by Rahul, Jun 29, 2005.

  1. Rahul

    Rahul Guest

    Consider the following:
    def a(x):
    return x+1

    def b(f):
    def g(*args,**kwargs):
    for arg in args:
    print arg
    return f(*args,**kwargs)
    return g

    a.__call__ = b(a.__call__)

    now calling a(1) and a.__call__(1) yield 2 different results!!
    i.e. for functions a(1) doesnt seem to be translated to a.__call__ if
    you assign a new value to a.__call__?
    i am using python 2.3.3
    somebody please clear this confusion
     
    Rahul, Jun 29, 2005
    #1
    1. Advertising

  2. Rahul wrote:
    > Consider the following:
    > def a(x):
    > return x+1
    >
    > def b(f):
    > def g(*args,**kwargs):
    > for arg in args:
    > print arg
    > return f(*args,**kwargs)
    > return g
    >
    > a.__call__ = b(a.__call__)
    >
    > now calling a(1) and a.__call__(1) yield 2 different results!!
    > i.e. for functions a(1) doesnt seem to be translated to a.__call__ if
    > you assign a new value to a.__call__?


    I don't know why this happens, but setting the __call__ attribute of a
    is a pretty strange thing to do. Why not just set a instead? The
    original function a(x) will still be stored as a closure in what is
    returned from b().

    If this is of purely academic interest then the answer is I don't know. :)
    --
    Michael Hoffman
     
    Michael Hoffman, Jun 29, 2005
    #2
    1. Advertising

  3. Just a guess, but setting "__X__" special methods won't work in most cases
    because these are usually optimized when the class is created.

    It might work if a.__call__ did exist before (because class a: contained
    a __call__ definition).

    Andreas

    On Wed, Jun 29, 2005 at 09:15:45AM +0100, Michael Hoffman wrote:
    > Rahul wrote:
    > > Consider the following:
    > > def a(x):
    > > return x+1
    > >
    > > def b(f):
    > > def g(*args,**kwargs):
    > > for arg in args:
    > > print arg
    > > return f(*args,**kwargs)
    > > return g
    > >
    > > a.__call__ = b(a.__call__)
    > >
    > > now calling a(1) and a.__call__(1) yield 2 different results!!
    > > i.e. for functions a(1) doesnt seem to be translated to a.__call__ if
    > > you assign a new value to a.__call__?

    >
    > I don't know why this happens, but setting the __call__ attribute of a
    > is a pretty strange thing to do. Why not just set a instead? The
    > original function a(x) will still be stored as a closure in what is
    > returned from b().
    >
    > If this is of purely academic interest then the answer is I don't know. :)
    > --
    > Michael Hoffman
    > --
    > http://mail.python.org/mailman/listinfo/python-list
     
    Andreas Kostyrka, Jun 29, 2005
    #3
  4. Rahul

    Rahul Guest

    Hi.
    well if you do dir(a) just after defining 'a' then it does show
    '__call__'.
    the reason i wanted to do it is that i wanted to see if theres a
    uniform way to wrap a function and callable objects so that for
    example i can get some message printed whenever a function or a
    function-like-object is called. then i could simply do :

    def wrapper(obj):
    g = obj.__call__
    def f(*args,**kwargs):
    for arg in args:print arg
    return g(*args,**kwargs)
    obj.__call__=f
    but it seems this will not work for functions :(


    Andreas Kostyrka wrote:
    > Just a guess, but setting "__X__" special methods won't work in most cases
    > because these are usually optimized when the class is created.
    >
    > It might work if a.__call__ did exist before (because class a: contained
    > a __call__ definition).
    >
    > Andreas
    >
    > On Wed, Jun 29, 2005 at 09:15:45AM +0100, Michael Hoffman wrote:
    > > Rahul wrote:
    > > > Consider the following:
    > > > def a(x):
    > > > return x+1
    > > >
    > > > def b(f):
    > > > def g(*args,**kwargs):
    > > > for arg in args:
    > > > print arg
    > > > return f(*args,**kwargs)
    > > > return g
    > > >
    > > > a.__call__ = b(a.__call__)
    > > >
    > > > now calling a(1) and a.__call__(1) yield 2 different results!!
    > > > i.e. for functions a(1) doesnt seem to be translated to a.__call__ if
    > > > you assign a new value to a.__call__?

    > >
    > > I don't know why this happens, but setting the __call__ attribute of a
    > > is a pretty strange thing to do. Why not just set a instead? The
    > > original function a(x) will still be stored as a closure in what is
    > > returned from b().
    > >
    > > If this is of purely academic interest then the answer is I don't know. :)
    > > --
    > > Michael Hoffman
    > > --
    > > http://mail.python.org/mailman/listinfo/python-list
     
    Rahul, Jun 29, 2005
    #4
  5. Rahul wrote:
    > def wrapper(obj):
    > g = obj.__call__
    > def f(*args,**kwargs):
    > for arg in args:print arg
    > return g(*args,**kwargs)
    > obj.__call__=f
    > but it seems this will not work for functions :(


    def wrap(obj):
    def f(*args, **kwargs):
    for arg in args:
    print arg
    return obj(*args, **kwargs)
    return f

    @wrap
    def func(a, b, c):
    ...

    class C(object):
    ...
    C = wrap(C)

    STeVe
     
    Steven Bethard, Jun 29, 2005
    #5
  6. Rahul

    Rahul Guest

    If you do C = wrap(C) C no longer remains a class..it becomes a
    function.

    Steven Bethard wrote:
    > Rahul wrote:
    > > def wrapper(obj):
    > > g = obj.__call__
    > > def f(*args,**kwargs):
    > > for arg in args:print arg
    > > return g(*args,**kwargs)
    > > obj.__call__=f
    > > but it seems this will not work for functions :(

    >
    > def wrap(obj):
    > def f(*args, **kwargs):
    > for arg in args:
    > print arg
    > return obj(*args, **kwargs)
    > return f
    >
    > @wrap
    > def func(a, b, c):
    > ...
    >
    > class C(object):
    > ...
    > C = wrap(C)
    >
    > STeVe
     
    Rahul, Jun 29, 2005
    #6
  7. Rahul wrote:
    > If you do C = wrap(C) C no longer remains a class..it becomes a
    > function.


    Does that matter?

    Reinhold
     
    Reinhold Birkenfeld, Jun 29, 2005
    #7
  8. Steven Bethard wrote:
    >
    > def wrap(obj):
    > def f(*args, **kwargs):
    > for arg in args:
    > print arg
    > return obj(*args, **kwargs)
    > return f
    >
    > @wrap
    > def func(a, b, c):
    > ...
    >
    > class C(object):
    > ...
    > C = wrap(C)


    Rahul top-posted:
    > If you do C = wrap(C) C no longer remains a class..it becomes a
    > function.


    And if you do
    func = wrap(func)
    which is the equivalent of
    @wrap
    def func(...):
    ...
    then func no longer has the same signature. But as Reinhold suggests,
    does that really matter? In the case of the class, you can still call
    it to create class instances. In the case of the function, you can
    still call it to retrieve return values. Why do you care about the type
    of the object?

    In the case that it does matter, e.g. you want to be able to invoke your
    methods from the class instead of the instance, you can wrap the
    specific function that you need wrapped, e.g.

    class C(object):
    @wrap
    def __new__(cls, *args):
    super(C, cls).__new__(cls, *args)
    ...

    STeVe
     
    Steven Bethard, Jun 29, 2005
    #8
  9. Rahul

    Rahul Guest

    Hi.
    I understood your point.
    thanks...
    rahul
    Steven Bethard wrote:
    > Steven Bethard wrote:
    > >
    > > def wrap(obj):
    > > def f(*args, **kwargs):
    > > for arg in args:
    > > print arg
    > > return obj(*args, **kwargs)
    > > return f
    > >
    > > @wrap
    > > def func(a, b, c):
    > > ...
    > >
    > > class C(object):
    > > ...
    > > C = wrap(C)

    >
    > Rahul top-posted:
    > > If you do C = wrap(C) C no longer remains a class..it becomes a
    > > function.

    >
    > And if you do
    > func = wrap(func)
    > which is the equivalent of
    > @wrap
    > def func(...):
    > ...
    > then func no longer has the same signature. But as Reinhold suggests,
    > does that really matter? In the case of the class, you can still call
    > it to create class instances. In the case of the function, you can
    > still call it to retrieve return values. Why do you care about the type
    > of the object?
    >
    > In the case that it does matter, e.g. you want to be able to invoke your
    > methods from the class instead of the instance, you can wrap the
    > specific function that you need wrapped, e.g.
    >
    > class C(object):
    > @wrap
    > def __new__(cls, *args):
    > super(C, cls).__new__(cls, *args)
    > ...
    >
    > STeVe
     
    Rahul, Jun 29, 2005
    #9
    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. Patrick Lioi
    Replies:
    7
    Views:
    353
    Beni Cherniavsky
    Aug 19, 2003
  2. chenyu
    Replies:
    1
    Views:
    300
  3. Robert Ferrell

    Redefining __call__ in an instance

    Robert Ferrell, Jan 15, 2004, in forum: Python
    Replies:
    5
    Views:
    368
    John Roth
    Jan 21, 2004
  4. Robert Brewer

    RE: Redefining __call__ in an instance

    Robert Brewer, Jan 16, 2004, in forum: Python
    Replies:
    1
    Views:
    434
    Jason Mobarak
    Jan 16, 2004
  5. Stefan Behnel

    changing __call__ on demand

    Stefan Behnel, Feb 13, 2005, in forum: Python
    Replies:
    11
    Views:
    514
    Steven Bethard
    Feb 14, 2005
Loading...

Share This Page