6

In the interest of reusing some existing code that was defined as an instance method of a different class, I was tying to do something like the following:

class Foo(object):
  def __init__(self):
    self.name = "Foo"

  def hello(self):
    print "Hello, I am " + self.name + "."

class Bar(object):
  def __init__(self):
    self.name = "Bar"


bar = Bar()
Foo.hello(bar)

but that results in:

TypeError: unbound method hello() must be called with Foo instance as first argument (got Bar instance instead)

Is something like this possible?


I should have been clear that I know this is a bad idea. Obviously the real solution is a bit of refactoring. I just figured there must be a way, and it turns out there is.

Thanks for the comments.

Jason DeFontes
  • 2,205
  • 14
  • 14
  • 1
    Looks like Python gave you your answer. This is the wrong approach for reusing existing code, anyway. – FogleBird Apr 24 '09 at 02:42
  • Why don't you want to factor out the common functionality and call it from the instance methods of both Foo and Bar? – Nathan Kitchen Apr 24 '09 at 03:08
  • Yes, this is clearly the wrong approach. I just assumed it could be done due to Python's dynamic nature, and was a little surprised when it didn't work as I expected. – Jason DeFontes Apr 24 '09 at 05:25
  • -1: This approach is so unsound it gives me the willies. If it can be done, it should be prohibited as being intentionally misleading. – S.Lott Apr 24 '09 at 10:03
  • remember that Python is strongly typed and originated at a [centre for mathematics](http://en.wikipedia.org/wiki/Centrum_Wiskunde_%26_Informatica). not surprisingly it signals a TypeError! – mariotomo Feb 15 '11 at 08:20

4 Answers4

9

Looks like this works:

Foo.hello.im_func(bar)

Hello, I am Bar.

I guess I need to read a this little harder...

Jason DeFontes
  • 2,205
  • 14
  • 14
5

It happens because python wraps class functions as an "unbound method" which performs this type checking. There's some description of the decisions involved in this here.

Note that this type checking has actually been dropped in python 3 (see the note at the end of that article), so your approach will work there.

Brian
  • 107,377
  • 28
  • 104
  • 109
2

This is an old question, but Python has evolved and looks like it's worth pointing it out:

with Python 3 there's no more <unbound method C.x>, since an unbound method is simply a <function __main__.C.x>!

Which probably means the code in the original question should not be considered /that/ off. Python has always been about duck typing in any case, hasn't it?!

Refs:

Alternative solution in Py2

Note that there's also an alternative solution to the "explorative" question (see Python: Bind an Unbound Method?):

In [6]: a = A.a.im_func.__get__(B(), B)

In [7]: a
Out[7]: <bound method B.a of <__main__.B instance at 0x7f37d81a1ea8>>

In [8]: a(2)
2

Ref:

Some ipython code samples

python 2

In [1]: class A():
    def a(self, a=0):
        print a
   ...:

In [2]: A.a
Out[2]: <unbound method A.a>

In [3]: A.a.im_func
Out[3]: <function __main__.a>

In [4]: A.a(B())
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-7694121f3429> in <module>()
----> 1 A.a(B())

TypeError: unbound method a() must be called with A instance as first argument (got B instance instead)

python 3

In [2]: class A():
    def a(self, a=0):
        print(a)
   ...:

In [3]: def a():
   ...:     pass
   ...:

In [4]: class B():
   ...:     pass

In [5]: A.a(B())
0

In [6]: A.a
Out[6]: <function __main__.A.a>
Community
  • 1
  • 1
Stefano
  • 16,056
  • 11
  • 59
  • 79
0

A while back I wondered about the same "feature" in Perl on PerlMonks, and the general consensus was that while it works (as it does in Python) you should not be doing things that way.

Thilo
  • 241,635
  • 91
  • 474
  • 626