Wednesday, September 3, 2008

Why does a method becomes bound method when it is accessed with an instance?

Short answer:

Because it is part of Python specification.

Long answer:

It is something to do with __get__ special method.
If an attribute has a method __get__, it is called when the attribute is accessed with . (dot)


>>> class C(object):
... def __get__(*arg):
... print "hello", arg
...
>>> class D(object):
... d = C()
...
>>> D.__dict__["d"]
<__main__.C object at 0x00B32CB0>
>>> D.d
hello (<__main__.C object at 0x00B32CB0>, None, <class '__main__.D'>)
>>> D().d
hello (<__main__.C object at 0x00B32CB0>, <__main__.D object at 0x00B32CD0>, <cl
ass '__main__.D'>)

When you define a function, Python creates a function object and a function object has __get__ method.

>>> def f():pass
...
>>> f
<function f at 0x00B2EF30>
>>> dir(f)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__ge
tattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__r
educe__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure',
'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_na
me']

and when you call __get__ of the function object, guess what will be returned?

>>> f.__get__(D())
<bound method ?.f of <__main__.D object at 0x00B32D90>>

Yeah it returns a bound method. That's why a method becomes bound method when it is accessed with an instance.

The short answer is a Python specification and the long answer is its implementation. property is also implemented with __get__.

>>> dir(property(f))
['__class__', '__delattr__', '__delete__', '__doc__', '__get__', '__getattribute
__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__
', '__set__', '__setattr__', '__str__', 'fdel', 'fget', 'fset']


Sep. 5 added:

> This is called the descriptor protocol.
>
> See the following for a long description of descriptors:
>
> http://users.rcn.com/python/download/Descriptor.htm

Thanx Fuzzyman!

2 comments:

Fuzzyman said...

This is called the descriptor protocol.

See the following for a long description of descriptors:

http://users.rcn.com/python/download/Descriptor.htm

hohehohe2 [at] gmail.com said...

Hi fuzzyman,
Wow it's a very good guide.
Thanks!