473,467 Members | 2,005 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

changing __call__ on demand

Hi!

This somewhat puzzles me:

Python 2.4 (#1, Feb 3 2005, 16:47:05)
[GCC 3.3.4 (pre 3.3.5 20040809)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

..>>> class test(object):
.... def __init__(self):
.... self.__call__ = self.__call1
.... def __call1(self):
.... print 1
.... def __call__(self):
.... print 2
....
..>>> t = test()
..>>> t()
2

If I take out the __call__ method completely and only set it in __init__, I
get a TypeError saying that test is not callable.

I want to use this in order to provide different implementations based on the
object configuration. Calculating the right function to call is non-trivial
and calls are frequent, so I want to change __call__ in order to run the right
function directly.

I know, I could use another level of indirection:

def __call__(self):
self.the_right_method()

and then set the_right_method accordingly, but I find that somewhat
sub-optimal. Is there a way to change __call__ after class creation?

Stefan
Jul 18 '05 #1
11 1852
I tried this:
class test(object): .... def __call1(self):
.... print 1
.... __call__ = __call1
....t = test()
t() 1

Is that what you were looking for?

--
Alan McIntyre
ESRG LLC
http://www.esrgtech.com

Stefan Behnel wrote: Hi!

This somewhat puzzles me:

Python 2.4 (#1, Feb 3 2005, 16:47:05)
[GCC 3.3.4 (pre 3.3.5 20040809)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

.>>> class test(object):
... def __init__(self):
... self.__call__ = self.__call1
... def __call1(self):
... print 1
... def __call__(self):
... print 2
...
.>>> t = test()
.>>> t()
2

If I take out the __call__ method completely and only set it in
__init__, I get a TypeError saying that test is not callable.

I want to use this in order to provide different implementations based
on the object configuration. Calculating the right function to call is
non-trivial and calls are frequent, so I want to change __call__ in
order to run the right function directly.

I know, I could use another level of indirection:

def __call__(self):
self.the_right_method()

and then set the_right_method accordingly, but I find that somewhat
sub-optimal. Is there a way to change __call__ after class creation?

Stefan


Jul 18 '05 #2
Stefan Behnel wrote:
Is there a way to change __call__ after class creation?


__call__, like __getitem__, and __getattr__ is called on the
class object, not the instance object. So, no, not as far as I
am aware, without using metaclass trickery. The simplest option
IMO is to use another level of indirection as you suggest.
--
Michael Hoffman
Jul 18 '05 #3
Alan McIntyre wrote:
class test(object):

... def __call1(self):
... print 1
... __call__ = __call1
Is that what you were looking for?


That still only allows him to have one call function per class.
--
Michael Hoffman
Jul 18 '05 #4

Michael Hoffman schrieb:
__call__, like __getitem__, and __getattr__ is called on the
class object, not the instance object. So, no, not as far as I
am aware, without using metaclass trickery. The simplest option
IMO is to use another level of indirection as you suggest.


Thanks for the quick answer. I didn't know they were class-level methods. Too
bad. Guess I'll stick with indirection then.

Stefan
Jul 18 '05 #5
Stefan Behnel wrote:
Is there a way to change __call__ after class creation?


Check out this thread on the topic:

http://mail.python.org/pipermail/pyt...ry/203142.html

Basically, the answer is no -- at least not on a per-instance basis.
You can try something like:

py> class Test(object):
.... def __new__(cls):
.... cls.__call__ = cls.call1
.... return object.__new__(cls)
.... def call1(self):
.... print 'call1'
.... def __call__(self):
.... print '__call__'
....
py> Test()()
call1

But then the call method is changed for all instances:

py> class Test(object):
.... instances = 0
.... def __new__(cls):
.... if cls.instances == 1:
.... print "setting __call__"
.... cls.__call__ = cls.call1
.... cls.instances += 1
.... return object.__new__(cls)
.... def call1(self):
.... print 'call1'
.... def __call__(self):
.... print '__call__'
....
py> t1 = Test()
py> t1()
__call__
py> t2 = Test()
setting __call__
py> t2()
call1
py> t1()
call1

Steve
Jul 18 '05 #6
Stefan Behnel wrote:
Hi!

This somewhat puzzles me:

Python 2.4 (#1, Feb 3 2005, 16:47:05)
[GCC 3.3.4 (pre 3.3.5 20040809)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

.>>> class test(object):
... def __init__(self):
... self.__call__ = self.__call1
... def __call1(self):
... print 1
... def __call__(self):
... print 2
...
.>>> t = test()
.>>> t()
2


It works the way you want if test is an old-style class:
class test: ... def __init__(self):
... self.__call__ = self.__call1
... def __call1(self):
... print 1
... def __call__(self):
... print 2
... t=test()
t()

1

Kent
Jul 18 '05 #7
Thanks; I didn't read close enough. :)

--
Alan McIntyre
ESRG LLC
http://www.esrgtech.com

Michael Hoffman wrote:
Alan McIntyre wrote:
>>>class test(object):

... def __call1(self):
... print 1
... __call__ = __call1
Is that what you were looking for?

That still only allows him to have one call function per class.

Jul 18 '05 #8
Stefan Behnel wrote:

Thanks for the quick answer. I didn't know they were class-level
methods. Too bad. Guess I'll stick with indirection then.


Here is one way of doing that indirection I just thought of--have
the class __call__ attribute call on the instance __call__
attribute:
class MyClass(object): .... def __init__(self, func):
.... self.__call__ = func
.... def __call__(self, *args, **keywds):
.... return self.__call__(*args, **keywds)
.... def f1(): return "foo" .... def f2(x, y): return x+y .... MyClass(f1)() 'foo' MyClass(f2)(30, 12)

42

I still can't figure out whether this is elegant, or opaque and
to be avoided. <wink>
--
Michael Hoffman
Jul 18 '05 #9
Stefan Behnel wrote:
Hi!

This somewhat puzzles me:

Python 2.4 (#1, Feb 3 2005, 16:47:05)
[GCC 3.3.4 (pre 3.3.5 20040809)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

.>>> class test(object):
... def __init__(self):
... self.__call__ = self.__call1
... def __call1(self):
... print 1
... def __call__(self):
... print 2
...
.>>> t = test()
.>>> t()
2

If I take out the __call__ method completely and only set it in
__init__, I get a TypeError saying that test is not callable.


Note that it works just fine if you don't use a new-style class:
class Test: .... def __init__(self):
.... self.__call__ = self.foobar
.... def foobar(self, *args, **kwargs):
.... print "Called with:", args, kwargs
.... t = Test()
t() Called with: () {} t(3, 4) Called with: (3, 4) {} t(42, x=0)

Called with: (42,) {'x': 0}

--
Hans Nowak
http://zephyrfalcon.org/

Jul 18 '05 #10
Le Sun, 13 Feb 2005 13:19:03 -0500, Hans Nowak a écrit :
Stefan Behnel wrote:
Hi!

This somewhat puzzles me:

Python 2.4 (#1, Feb 3 2005, 16:47:05)
[GCC 3.3.4 (pre 3.3.5 20040809)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

.>>> class test(object):
... def __init__(self):
... self.__call__ = self.__call1 # self.__call__ is bound
... def __call1(self):
... print 1
... def __call__(self): # self.__call__ is rebound
... print 2
...
.>>> t = test()
.>>> t()
2 2 because the last defined __call__ wins. Try dir(t)

If I take out the __call__ method completely and only set it in
__init__, I get a TypeError saying that test is not callable.
This seems logical.
Note that it works just fine if you don't use a new-style class:
class Test: ... def __init__(self):
... self.__call__ = self.foobar
... def foobar(self, *args, **kwargs):
... print "Called with:", args, kwargs
... t = Test()
t() Called with: () {} t(3, 4) Called with: (3, 4) {} t(42, x=0)
Called with: (42,) {'x': 0}

Are you sure that if you add a __call__() method, it will still work
fine ?
Regards

Jul 18 '05 #11
F. Petitjean wrote:
Le Sun, 13 Feb 2005 13:19:03 -0500, Hans Nowak a écrit :
Note that it works just fine if you don't use a new-style class:
>class Test:


... def __init__(self):
... self.__call__ = self.foobar
... def foobar(self, *args, **kwargs):
... print "Called with:", args, kwargs
...
>t = Test()
>t()


Called with: () {}
>t(3, 4)


Called with: (3, 4) {}
>t(42, x=0)


Called with: (42,) {'x': 0}


Are you sure that if you add a __call__() method, it will still work
fine ?


Simple enough to check, isn't it?

py> class C:
.... def __init__(self):
.... self.__call__ = lambda: "__init__"
.... def __call__(self):
.... return "__call__"
....
py> C()()
'__init__'

Old-style classes lookup methods like __call__ on the instance[1].
New-style classes look them up on the type:

py> class C:
.... def __init__(self):
.... self.__iter__ = lambda: iter(["__init__"])
.... def __iter__(self):
.... return iter(["__call__"])
....
py> list(C())
['__init__']
py> class C(object):
.... def __init__(self):
.... self.__iter__ = lambda: iter(["__init__"])
.... def __iter__(self):
.... return iter(["__call__"])
....
py> list(C())
['__call__']

AFAICT, non-magic methods are looked up on instance first:

py> class C:
.... def __init__(self):
.... self.f = lambda: "__init__"
.... def f(self):
.... return "__call__"
....
py> C().f()
'__init__'
py> class C(object):
.... def __init__(self):
.... self.f = lambda: "__init__"
.... def f(self):
.... return "__call__"
....
py> C().f()
'__init__'

STeVe

[1] Well, they look there first.
Jul 18 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Patrick Lioi | last post by:
def foo(): pass foo is a function foo is a callable object foo has method __call__ defined foo.__call__ is a function foo.__call__ is a callable object foo.__call__ has method __call__...
5
by: Robert Ferrell | last post by:
I have a question about assigning __call__ to an instance to make that instance callable. I know there has been quite a bit of discussion about this, and I've read all I can find, but I'm still...
8
by: Rahul | last post by:
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
7
by: ncf | last post by:
I have a feeling that this is highly unlikely, but does anyone in here know if it's possible to directly call a module, or will I have to wrap it up in a class? i.e., import MyMod...
5
by: Kent Johnson | last post by:
I am learning about metaclasses and there is something that confuses me. I understand that if I define a __call__ method for a class, then instances of the class become callable using function...
18
by: Chris Hills | last post by:
A lesson in Posting How many C.L.C group posters does it take to change a C light bulb? 1 to change the light bulb and to post that the light bulb has been changed 14 to share similar...
7
by: Gigs_ | last post by:
from Tkinter import * from tkFileDialog import askopenfilename from tkColorChooser import askcolor from tkMessageBox import askquestion, showerror from tkSimpleDialog import askfloat demos...
17
by: skip | last post by:
I don't personally use __call__ methods in my classes, but I have encountered it every now and then here at work in code written by other people. The other day I replaced __call__ with a more...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.