2

If I have an object of a certain type, and I would like to get the unbound method, should I use type(obj).method_name or obj.__class__.method_name? I got confused upon seeing the following result:

class ClassA(object):
  def Test(self):
    pass

obj_a = ClassA()

print obj_a.__class__ is type(obj_a)
print obj_a.__class__.Test is type(obj_a).Test 

The first returns True and the second False. So what is the difference of the two in the last statement?

UPDATE:

My use case is that I have some class in a playground notebook. The class objects may be heavy, for example, they contain stuff after long time of training. During the time I would like to make updates to the functions and keep use the existing objects. So I would like something like this to be working:

# In cell 1 I define the following class.
class ClassA(object):
  def Test(self):
    print 'haha'

# In cell 2 I create an object and use it for a while.
obj_a = ClassA()
obj_a.Test()

# After some time I modified the ClassA in cell 1 and re-executed the cell:
class ClassA(object):
  def Test(self):
    print 'hoho'

# Then I want to replace a method and call Test again:
obj_a.__class__.Test = ClassA.Test
obj_a.Test()  # Should print 'hoho'

Unfortunately the above code does not work. The last call obj_a.Test() uses the unbound method Test.

shaoyl85
  • 1,854
  • 18
  • 30
  • @user3100115: I thought they should both return the type object of `obj_a`? – shaoyl85 Feb 28 '16 at 06:23
  • why would you want to get the method of the class? That's practically useless. Take the method from an instance ``obj_a.Test``. – MSeifert Feb 28 '16 at 06:23
  • That would give me a bounded method.. – shaoyl85 Feb 28 '16 at 06:27
  • If you compare the two by `==` instead of `is`, you will find them to be two equal (yet not identical) unbound method objects. `__class__` and `type()`, on the other hand, both return the identical (since only) type `ClassA`. – user2390182 Feb 28 '16 at 06:31
  • Maybe I'm wrong but if you take an unbound method from a class you need to pass the first argument (``self``) explicitly. So you unbound it to bind it at call-time? Your question is interesting but I cannot see any real use-case here. Also with python 3.5 both statements return True on my computer. – MSeifert Feb 28 '16 at 06:31
  • In Py3, these both return True. Not sure why the second doesn't return True for py2, checking the `id`s they are identical. – AChampion Feb 28 '16 at 06:33
  • @schwobaseggl: I see. The `.Test` may be returning a dynamically constructed unbound method, such that the two are equal but not identical. Not sure though. – shaoyl85 Feb 28 '16 at 06:34
  • @AChampion: Interesting. There must be something I didn't understand about `is`. – shaoyl85 Feb 28 '16 at 06:35
  • @MSeifert: Do you mean the "unbound" is some procedure that is performed under the hood? Do you know what is the procedure? – shaoyl85 Feb 28 '16 at 06:36
  • This is the expected behaviour is. change the second example to: `a = obj_a.__class__.Test` `b = type(obj_a).Test` `a is b` will return `True` – styvane Feb 28 '16 at 06:39
  • @shaoyl85 - Just try ``obj_a.__class__.Test()`` (unbound method) and then try ``obj_a.__class__.Test(obj_a)`` (unbound method with binding at call time). If you want a "unbound" method use ``@staticmethod`` or ``@classmethod`` – MSeifert Feb 28 '16 at 06:39
  • @user3100115 Hmm.. it is still False for me (Python 2.7.10). – user2390182 Feb 28 '16 at 06:40
  • @shaoyl85 this can be boiled down to `ClassA.Test is ClassA.Test` returns `False` in Py2, this seems very strange. – AChampion Feb 28 '16 at 06:43
  • Thank you for all the suggestions. I updated the question with some motivation. Would you have a look again? – shaoyl85 Feb 28 '16 at 06:44
  • @schwobaseggl yes False in Python2.x and True in Python3.x – styvane Feb 28 '16 at 06:46
  • @shaoyl85 - If you can use Python3, your example is working there because from python3 on methods are just functions (there is no real bound function anymore). Not really sure if that's exactly true but it's true enough for your example. You should probably add a ``Python 2`` tag to the question because the question is irrelevant for python 3. – MSeifert Feb 28 '16 at 06:49
  • Possible duplicate of [python bound and unbound method object](http://stackoverflow.com/questions/13348031/python-bound-and-unbound-method-object) – styvane Feb 28 '16 at 06:59

2 Answers2

2

The answer to your question, you need to assign to the bound method, e.g.:

import types
obj_a.Test = types.MethodType(ClassA.Test, obj_a)
obj_a.Test()

Would give the result you expect, i.e. 'hoho'

Updated: Here's an example:

import types

class ClassA(object):
    def Test(self):
        print 'haha'

obj = ClassA()
obj.Test()
# haha

Update ClassA to hoho:

obj.__class__ = ClassA
obj.Test()
# hoho
AChampion
  • 29,683
  • 4
  • 59
  • 75
  • Thank you! Are you trying it in Python 3? It doesn't seem to work for me. – shaoyl85 Feb 28 '16 at 06:54
  • I see. My use case is little different. In the ipython notebook, I modify on the `Test` method directly and then execute that cell. In this case a new class will be created with the same name "ClassA". I would like to replace the `Test` method in `obj` with the method `Test` in the new class `ClassA`. Is there a way of doing so? – shaoyl85 Feb 28 '16 at 07:01
  • You will also need to assign `obj.__class__ == ClassA` as it is a new `ClassA` for it to work correctly, fixed above. – AChampion Feb 28 '16 at 07:05
  • Actually, just `obj.__class__ = ClassA` is enough. There is no need for the `MethodType`. Thanks again. – shaoyl85 Feb 28 '16 at 07:11
  • Thanks, updated - I initially tried that and got an error but tested again and it works fine. – AChampion Feb 28 '16 at 07:14
2

You can try also :

obj_a.__class__.Test is obj_a.__class__.Test
type(obj_a).Test is type(obj_a).Test

which both are equivalent to ClassA.Test is ClassA.Test, but all of them returns False.

Explanation for this is the particular behavior unbounded methods, see here.

Community
  • 1
  • 1
yoch
  • 343
  • 3
  • 8
  • Interesting. The `.Test` may not be returning an existing object, but are dynamically constructing one. – shaoyl85 Feb 28 '16 at 06:56
  • Btw, this is explained in http://stackoverflow.com/questions/13348031/python-bound-and-unbound-method-object – shaoyl85 Feb 28 '16 at 07:10