functions, classes, bound, unbound?

Steven Bethard steven.bethard at gmail.com
Sun Mar 25 17:09:02 EDT 2007


On Mar 25, 9:13 am, "7stud" <bbxx789_0... at yahoo.com> wrote:
 > Is there some other way to retrieve a user-defined function object
 > from a class other than using the class name or an instance?

On Mar 25, 3:00 am, irs... at gmail.com wrote:
 > What Steven B. already said, MyClass.__dict__['someFunc'], is a
 > different way than MyClass.someFunc that produces different results.

7stud wrote:
> That doesn't seem to fit what GvR was talking about.  From this
> example:
> 
> class Test(object):
>         def greet():
>                 print "Hello"
> 
> methObj = Test.__dict__["greet"]
> print methObj.im_self
> 
> I get this output:
> 
> Traceback (most recent call last):
>   File "test1.py", line 7, in ?
>     print methObj.im_self
> AttributeError: 'function' object has no attribute 'im_self'


Yep.  The thing in the class __dict__ is the original *function*. The 
thing you get from something like ``Test.greet`` is the *method*. 
Here's another way of looking at it::

     >>> class Test(object):
     ...     pass
     ...
     >>> def greet():
     ...     print 'Hello'
     ...
     >>> greet
     <function greet at 0x00E718B0>
     >>> Test.greet = greet
     >>> Test.__dict__['greet']
     <function greet at 0x00E718B0>
     >>> Test.__dict__['greet'] is greet
     True

Note that ``Test.__dict__['greet']`` is the ``greet`` *function*, not 
some wrapper of that function. When you access the class attribute 
normally, Python creates an 'unbound method' object::

     >>> Test.greet
     <unbound method Test.greet>
     >>> Test.greet is greet
     False
     >>> Test.greet.im_func
     <function greet at 0x00E718B0>
     >>> Test.greet.im_func is greet
     True

See that ``Test.greet`` gives you an 'unbound method' object which just 
wraps the real 'function' object (which is stored as the 'im_func' 
attribute)?  That's because under the covers, classes are actually using 
doing something like this::

     >>> Test.__dict__['greet'].__get__(None, Test)
     <unbound method Test.greet>
     >>> Test.greet == Test.__dict__['greet'].__get__(None, Test)
     True

So if you want to get a method from a function, you can always do that 
manually yourself::

     >>> greet.__get__(None, Test)
     <unbound method Test.greet>

Hope that helps,

STeVe



More information about the Python-list mailing list