6

I know I can attach a function to a class and make it a method:

 >>> def is_not_bound(inst, name):
...     print("Hello %s" % name)
... 
>>> 
>>> class NoMethods:
...     pass
... 
>>> 
>>> setattr(NoMethods, 'bound', is_not_bound)
>>> 
>>> NoMethods().bound("oz") # prints: Hello oz
Hello oz

To my surprise this works also with a bound method from one class to another:

>>> class Foo:
...     def foo(self, name):
...         print("Hello %s" % name)
... 
>>> class B:
...     pass
... 
>>> setattr(B, 'bound_to_b', getattr(Foo, 'foo'))
>>> B().bound_to_b("confused?")
Hello confused?
>>> 

Can I safely use this? Is there something I am overseeing?

update

One caveat that I found already:

>>> B.bound_to_b
<function Foo.foo at 0x7fc997e8b730>

Even though I called the method from B, It seems bound to Foo.

And even more surprising!:

>>> def new_method(self, addto):
...     return self.num + addto
... 
>>> setattr(B, 'add', new_method)
>>> b=B()
>>> b.num = 2
>>> b.add(2)
4
oz123
  • 23,317
  • 25
  • 106
  • 169
  • Yes, there's nothing wrong with doing that. Python doesn't really have methods; a function defined in a class is still a function. (Assuming you're using python 3.) – Aran-Fey Mar 29 '18 at 09:28
  • 1
    Which part of the "even more surprising" code is surprising? – Aran-Fey Mar 29 '18 at 09:30
  • Actually, after reading it again, and seeing it's not Python 2, there is no bound or unboud. It's just a function. So, not surprisingly, it works! – oz123 Mar 29 '18 at 09:31
  • methods are just the reference, you just used the same reference of the exiting function. what's confusing in here? – Anonymous Mar 29 '18 at 09:35
  • 2
    Can you please clarify what surprises you about that last block of code? It all makes perfect sense to me. – Aran-Fey Mar 29 '18 at 09:39
  • well, considering that is was new for me. It's surprising. Not confusing. I was suprised that it worked. I didn't expect Python to be that awesome. – oz123 Mar 29 '18 at 09:39

1 Answers1

1

Apparently, this is an intended behavior (which is cool!). But also apparently, this behavior is not very familiar.

If you knew Python 2 for a long time, you would might not be aware of the fact that Python 3 has no methods (as commented above).

So in Python 3:

>>> class Foo:
...     def foo(self, name):
...         print("Hello %s" % name)
... 
>>> Foo.foo
<function Foo.foo at 0x7f729a406730>
>>> def foo():
...     pass
... 
>>> foo
<function foo at 0x7f729b83ff28>
>>> 
>>> Foo.foo
<function Foo.foo at 0x7f729a406730>

There is no distinction! In Python 2 however:

Python 2.7.14 (default, Feb  2 2018, 02:17:12) 
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo:
...     def foo(self, name):
...         print("Hello %s" % name)
... 
>>> Foo.foo
<unbound method Foo.foo>
>>> 
oz123
  • 23,317
  • 25
  • 106
  • 169
  • 2
    I don't see the point of this answer. All you've done is to repeat the things that have already been explained in [the question I linked](https://stackoverflow.com/questions/11949808/what-is-the-difference-between-a-function-an-unbound-method-and-a-bound-method). If _this_ answers your question, why not just mark the duplicate as accepted instead? – Aran-Fey Mar 29 '18 at 10:07
  • Because, people google this stuff, and the question you link answer also this question is titled differently. – oz123 Mar 29 '18 at 10:42
  • Okay, but the answer in the other question still answers your question. What's the point of repeating it? If the question is marked as a duplicate, people can go read the original (and more complete) answer. – Aran-Fey Mar 29 '18 at 10:53
  • The point is that the accepted answer is talking about bound\unbound methods. Python 3 hasn't got those. It's a similar topic, but this question is much more specific. – oz123 Mar 29 '18 at 11:26