methods and functions, instances and classes

Bruno Desthuilliers onurb at xiludom.gro
Mon Sep 4 13:07:36 EDT 2006


David Isaac wrote:
> When I create an instance of a class,
> are the class's functions *copied* to create the methods?

No, unless you explicitely do it.

> Or are method calls actually calls of the class's functions?

Depends on how the method was associated to the instance (you can set
methods on a per-instance property), but in the general case (functions
defined in the class body), yes.

> I am sure this is both obvious

I once had the same question when I was learning computers and programming.

> and FAQ,

Not AFAIK.

> but I did not find a clear answer
> (e.g. here
> http://docs.python.org/tut/node11.html#SECTION0011340000000000000000 ,
> a lot turns on the meaning of 'equivalent'.)


"""
If the name denotes a valid class attribute that
is a function object, a method object is created by packing (pointers
to) the instance object and the function object just found together in
an abstract object: this is the method object. When the method object is
called with an argument list, it is unpacked again, a new argument list
is constructed from the instance object and the original argument list,
and the function object is called with this new argument list.
"""

IOW, a method object is a callable object keeping references to both the
instance and the function (note the "(pointers to) ... the function
object").

You could represent yourself the method as something like:

class Method(object):
  def __init__(self, im_func, im_self):
    self.im_self = obj
    self.im_func = func

  def __call__(self, *args, **kw):
    return self.im_func(self.im_self, *args, **kw)

Now suppose that the 'function' type definition (yes, Python functions
are objects) looks a bit like this:

class function(object):
    . . .
    def __get__(self, obj):
        return Method(self, obj)


And that looking up an attribute on an instance looks like this (dumbed
down of course):

def __getattribute__(self, name):
  if name in self.__dict__:
    return self.__dict__[name]
  elif hasattr(self.__class__, name)
    attrib = getattr(self.__class__, name)
    if hasattr(attrib, '__get__'):
      return attrib.__get__(self)
    else:
      return attrib
  else:
    raise AttributeError("object %s has no attribute %s" % (self, name)


Then for :

class Foo(object):
  def bar(self, val):
    return "%s %s" % (self, val)

foo = Foo()

Looking up 'bar' on 'foo':
bar = foo.bar

would resolve, thru __getattribute__ etc, to:
bar = Method(Foo.bar, foo)

Which, if then called, would resolve to
Foo.bar(foo, 42)



NB : reading the doc about new-style classes and the descriptor protocol
may help:
http://www.python.org/download/releases/2.2.3/descrintro/
http://users.rcn.com/python/download/Descriptor.htm

HTH
-- 
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb at xiludom.gro'.split('@')])"



More information about the Python-list mailing list