9

In python it's possible to use '.' in order to access object's dictionary items. For example:

class test( object ) :
  def __init__( self ) :
    self.b = 1
  def foo( self ) :
    pass
obj = test()
a = obj.foo

From above example, having 'a' object, is it possible to get from it reference to 'obj' that is a parent namespace for 'foo' method assigned? For example, to change obj.b into 2?

Nicolas Dumazet
  • 7,147
  • 27
  • 36
grigoryvp
  • 40,413
  • 64
  • 174
  • 277

3 Answers3

17

On bound methods, you can use three special read-only parameters:

  • im_func which returns the (unbound) function object
  • im_self which returns the object the function is bound to (class instance)
  • im_class which returns the class of im_self

Testing around:

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

instance = Test()
instance.foo          # <bound method Test.foo of <__main__.Test object at 0x1>>
instance.foo.im_func  # <function foo at 0x2>
instance.foo.im_self  # <__main__.Test object at 0x1>
instance.foo.im_class # <__main__.Test class at 0x3>

# A few remarks
instance.foo.im_self.__class__ == instance.foo.im_class # True
instance.foo.__name__ == instance.foo.im_func.__name__  # True
instance.foo.__doc__ == instance.foo.im_func.__doc__    # True

# Now, note this:
Test.foo.im_func != Test.foo # unbound method vs function
Test.foo.im_self is None

# Let's play with classmethods
class Extend(Test):
    @classmethod
    def bar(cls): 
        pass

extended = Extend()

# Be careful! Because it's a class method, the class is returned, not the instance
extended.bar.im_self # <__main__.Extend class at ...>

There is an interesting thing to note here, that gives you a hint on how the methods are being called:

class Hint(object):
    def foo(self, *args, **kwargs):
        pass

    @classmethod
    def bar(cls, *args, **kwargs):
        pass

instance = Hint()

# this will work with both class methods and instance methods:
for name in ['foo', 'bar']:
    method = instance.__getattribute__(name)
    # call the method
    method.im_func(method.im_self, 1, 2, 3, fruit='banana')

Basically, im_self attribute of a bound method changes, to allow using it as the first parameter when calling im_func

Nicolas Dumazet
  • 7,147
  • 27
  • 36
14

Python 2.6+ (including Python 3)

You can use the __self__ property of a bound method to access the instance that the method is bound to.

>> a.__self__
<__main__.test object at 0x782d0>
>> a.__self__.b = 2
>> obj.b
2

Python 2.2+ (Python 2.x only)

You can also use the im_self property, but this is not forward compatible with Python 3.

>> a.im_self
<__main__.test object at 0x782d0>
Miles
  • 31,360
  • 7
  • 64
  • 74
  • 3
    Using dir() is a good way to discover things like that: dir(obj.foo) – Miles Jun 05 '09 at 05:14
  • But i need to do exactly reverse operation: obj from a :) – grigoryvp Jun 05 '09 at 05:24
  • I mean at the interactive prompt, for learning purposes. You can look at what methods and attributes different kinds of objects have; so if you have an instance method, you can use dir() on it and see if any of the attributes lead you back to the object. And besides, dir(obj.foo) is identical to dir(a). – Miles Jun 05 '09 at 05:33
  • I think Miles was amused that you told him about two functions that do opposite things. Either way, I am amused. – Avery Richardson May 03 '15 at 20:12
  • Is that Python 3 ? I don't see im_self in 2.7.x – uchuugaka Aug 22 '16 at 02:13
  • @uchuugaka `im_self` is there in 2.7, but not in Python 3. – Miles Aug 22 '16 at 05:45
8

since python2.6 synonyms for im_self and im_func are __self__ and __func__, respectively. im* attributes are completely gone in py3k. so you would need to change it to:

>> a.__self__
<__main__.test object at 0xb7b7d9ac>
>> a.__self__.b = 2
>> obj.b
2
SilentGhost
  • 307,395
  • 66
  • 306
  • 293