[Tutor] Are the methods in a class copied or just linked to?

Steven D'Aprano steve at pearwood.info
Fri Jul 3 03:17:12 CEST 2015


On Thu, Jul 02, 2015 at 12:30:23PM -0700, Jim Mooney Py3.4.3winXP wrote:

> When an instance uses a class method, does it actually use the method that
> is in the class object's memory space, or is the method copied to the
> instance?

The first. And it is not just an implementation detail, it is part of 
Python's programming model.

When you define a class in you define methods and other attributes in 
the class namespace:

class C:
    attr = 23
    def method(self, arg):
        pass

'attr' and 'method' exist inside C.__dict__. That is, I believe, more 
than just implementation, I believe that is considered part of the 
language. For instance, this works in IronPython too:

>>> class C:
...     def method(self): pass
...
>>> C.__dict__['method']
<function method at 0x000000000000002B>


even though classes in IronPython are based on a completely different 
technology (the .Net CLR) from the standard CPython implementation.

When you create an instance, under normal circumstances it gets its own 
__dict__, but that does *not* get a copy of the method, nor even a 
reference to the original method. In IronPython again:

>>> c = X()
>>> c.__dict__ != C.__dict__  # Separate dictionaries?
True
>>> 'method' in c.__dict__  # in the instance?
False
>>> 'method' in C.__dict__  # in the class?
True


When you call a method, c.method(), Python does a name look-up. 
Simplified, it looks in c.__dict__, then C.__dict__, then the __dict__s 
of each of C's parents (if any).

The upshot of this is that you can actually override the method for a 
specific instance. In Ruby, this technique is called "singleton method", 
in Python it doesn't have a standard name, but it can be useful. It only 
works on classes with an instance __dict__, so it doesn't work on ints, 
floats, strings and other built-in types, and for technical reasons it 
doesn't work on magic __dunder__ methods, and it is a little fiddly to 
get working, but it does work:


>>> class C:
...     def method(self):
...         return "shared"
...
>>> c = C()
>>> d = C()
>>> from types import MethodType
>>> c.method = MethodType(lambda self: 'overridden', c)
>>> c.method()
'overridden'
>>> d.method()
'shared'



-- 
Steve


More information about the Tutor mailing list