David said:
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.
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