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)
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)
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
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
thanks!
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.
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?
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.
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.