function v. method

Duncan Booth duncan.booth at invalid.invalid
Tue Jul 18 03:42:20 EDT 2006


danielx wrote:

>>>> Foo.func = dan    # <-- Appearantly, something magical happens here, 
because...
>>>> Foo.func
><unbound method Foo.dan>
>>>> f = Foo.func
>>>> f is dan               # <-- things begins to look suprising here.
> False
>>>> ismethod(f)
> True
> 
> Imagine my surprise. Why would Python do this?
> 

Nothing magical happens at the point you said. The assignment is just an 
assignment and you saw that the function was stored unchanged when you 
looked in the class's dictionary.

The magic happens when you access a member of a class or an instance. If 
the value is a descriptor then its __get__ method is called. Roughly 
speaking, Foo.func is equivalent to:

>>> Foo.__dict__['func'].__get__(None, Foo)
<unbound method Foo.dan>

Python does this so that it can support other descriptor types such as 
property, classmethod, staticmethod.

You can see this happening if you define your own descriptor:

>>> class MyDesc(object):
    def __get__(self, *args):
        print "__get__ called", args
        return None

    
>>> d = MyDesc()
>>> Foo.oops = d
>>> Foo.oops
__get__ called (None, <class __main__.Foo at 0x00B3F930>)

http://docs.python.org/ref/descriptor-invocation.html has a description of 
this. Although it claims "Note that descriptors are only invoked for new 
style objects or classes (ones that subclass object() or type())." the 
descriptor mechanism is partially implemented for old style classes. 
Several aspects of descriptors don't work properly though in old-style 
classes which is one reason why you should always use new-style classes.

> Privates don't have to be entirely absent from Klass.__dict__
> (which would make Python not introspective); they can just be invisible
> when using the dot-syntax.

You could implement that using a data descriptor, but if you are going to 
prevent access to your private variables using the dot operator, then your 
code is going to look pretty silly with a lot of references to 
self.__dict__['theprivate'] which doesn't gain anything in readability over 
self.__theprivate.



More information about the Python-list mailing list