Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

substitution of a method by a callable object

6 views
Skip to first unread message

netimen

unread,
Oct 22, 2008, 12:13:52 PM10/22/08
to
Can I substitute a method of a class by a callable object (not a
function)? I can very easy insert my function in a class as a method,
but an object - can't.

I have the following:

class Foo(object):
pass

class Obj(object):
def __call__(self, obj_self):
print 'Obj'

def func(self):
print 'func'

f = Foo()
Foo.meth = func
f.meth() # all goes OK
Foo.meth = Obj()
f.meth() # I get TypeError: __call__() takes exactly 2 arguments (1
given)

Terry Reedy

unread,
Oct 22, 2008, 1:19:08 PM10/22/08
to pytho...@python.org
netimen wrote:
> Can I substitute a method of a class by a callable object (not a
> function)? I can very easy insert my function in a class as a method,
> but an object - can't.

Yes you can and did.

> class Foo(object):
> pass
>
> class Obj(object):
> def __call__(self, obj_self):
> print 'Obj'
>
> def func(self):
> print 'func'
>
> f = Foo()
> Foo.meth = func
> f.meth() # all goes OK
> Foo.meth = Obj()
> f.meth() # I get TypeError: __call__() takes exactly 2 arguments (1
> given)

So either remove the unused obj_self parameter from __call__ or pass
something -- anything -- to be bound to it.
f.meth(1) for instance, works fime (in 3.0 at least)

George Sakkis

unread,
Oct 22, 2008, 1:40:45 PM10/22/08
to

You have to wrap it as an (unbound) instance method explicitly:

from types import MethodType
Foo.meth = MethodType(Obj(), None, Foo)
f.meth()

For normal functions this seems to be done implicitly (of course you
can do it explicitly if you want):

>>> Foo.meth = func
>>> print Foo.meth
<unbound method Foo.func>

George

Bruno Desthuilliers

unread,
Oct 22, 2008, 12:46:22 PM10/22/08
to
netimen a écrit :

> Can I substitute a method of a class by a callable object (not a
> function)? I can very easy insert my function in a class as a method,
> but an object - can't.

functions implement the descriptor protocol so when looked up as class
attributes, the lookup invoke their __get__ method, which in turn
returns a method object (which is a thin wrapper around the function,
the class and the instance).

You can either build the method manually (as Georges explained), or make
your own Obj class a proper descriptor:

from types import MethodType

class Obj(object):
__name__ = "Obj" # for Method.__repr_

def __call__(self, obj_self):
print 'Obj'

def __get__(self, instance, cls):
return MethodType(self, instance, cls)


HTH

netimen

unread,
Oct 22, 2008, 3:42:04 PM10/22/08
to
On 22 окт, 20:46, Bruno Desthuilliers

thanks!

Terry Reedy

unread,
Oct 22, 2008, 4:34:44 PM10/22/08
to pytho...@python.org
George Sakkis wrote:
> On Oct 22, 12:13 pm, netimen <neti...@gmail.com> wrote:
>
>> Can I substitute a method of a class by a callable object (not a
>> function)? I can very easy insert my function in a class as a method,
>> but an object - can't.
>>
>> I have the following:
>>
>> class Foo(object):
>> pass
>>
>> class Obj(object):
>> def __call__(self, obj_self):
>> print 'Obj'
>>
>> def func(self):
>> print 'func'
>>
>> f = Foo()
>> Foo.meth = func
>> f.meth() # all goes OK
>> Foo.meth = Obj()
>> f.meth() # I get TypeError: __call__() takes exactly 2 arguments (1
>> given)
>
> You have to wrap it as an (unbound) instance method explicitly:

Nope. As the error message says, the method was called with nothing
provided to be bound to the extraneous parameter obj_self. Either
provide an arg, such as with f.meth(1), *or* delete obj_self and 'Obj'
is printed, with both 2.5 and 3.0.

netimen

unread,
Oct 22, 2008, 5:58:28 PM10/22/08
to

OK, I have implemented Bruno Desthuilliers example. But there is
another question: can I having a method determine if it is an instance
of given class. So:

class Obj(object):
__name__ = "Obj" # for Method.__repr_

def __call__(self, obj_self):
print 'Obj'

def __get__(self, instance, cls):
return MethodType(self, instance, cls)

class Foo(object):
pass

Foo.meth = Obj()

## in some another place of code
if isinstance(Foo.meth, Obj): # doesn't work because type(Foo.meth) is
now 'instancemethod'
...

Can I determine that?

Bruno Desthuilliers

unread,
Oct 22, 2008, 4:26:20 PM10/22/08
to
netimen a écrit :
(snip)

> OK, I have implemented Bruno Desthuilliers example. But there is
> another question: can I having a method determine if it is an instance
> of given class. So:

As the name imply, a method is usually, well, an instance of type
'method' !-)

> class Obj(object):
(snip)


>
> class Foo(object):
> pass
>
> Foo.meth = Obj()
>
> ## in some another place of code
> if isinstance(Foo.meth, Obj): # doesn't work because type(Foo.meth) is
> now 'instancemethod'

Indeed. I suppose what you want is to know if the callable wrapped by
the method is an instance of Obj ?

>
> Can I determine that?

Yeps. Test the im_func attribute of the method:

if isinstance(Foo.meth.im_func, Obj): print "yadda"

But you'd better put this in a try/except block, because a callable
attribute of a class is not necessarily a method - and so it may not
have an im_func attribute.

Also, may I ask why you want to check this ? Not that it's necessarily
wrong, but real use case for typechecking are pretty rare.

netimen

unread,
Oct 23, 2008, 1:34:34 AM10/23/08
to
On 23 окт, 00:26, Bruno Desthuilliers

Thanks! I have wasted much time playing with different Foo.meth trying
to get to Obj through them. But im_func was one of the fields I
haven't checked )

Indeed, I have managed already without that. The task was to
substitute __str__ method by a complex formatter. It called a low-
level formatter, a function wich returned simple str(self). That
function could be called with objects with substituted formatters and
with simple objects. So to avoid recursion I wanted to check wether
the formatter of my object was substituted.

0 new messages