Our good friend Randall was talking about how he liked prototype inheritance such as that in JavaScript. He enjoyed how you can add, modify and remove methods from JavaScript classes and have them apply to all object instances.

Amazed as he was, he's now forcing me at gun point to write a post about it!

The first thing you have to understand about Python classes is that all they are is a collection of references to members. Methods are just function pointers that are referenced by the class, not embedded or copied into the class. This is why all methods require that the first parameter be self, the current instance. Instances themselves contain the real state and reference the class. When you invoke a method on the instance it looks up what function to call.

So if you have two instances of the same class, the methods hanging off them are really the same function.

As they say, the prove is in the pudding.

# A basic class
class ClassA:
  def methodA(self):
    return True
a = ClassA()
b = ClassA()
# Verify that they have the same function address
id(a.methodA) == id(b.methodA)

Since class functions do not get copied into instances you can make changes to the class and have it apply to all existing and future instances. Just as you would in JavaScript or any other prototype based object language.

Following on from the previous snippet let's add, modify and remove references to methods and observe how they impact the instances.

# Let's add a new method
setattr(ClassA, "methodB", lambda self : 5)
# Verify it exists and returns 5
a.methodB() == 5
b.methodB() == 5
# Lets modify methodA
setattr(ClassA, "methodA", lambda self : False)
# Let's verify this method now returns False rather than True.
a.methodA() == False
b.methodA() == False
# Let's remove methodA
delattr(ClassA, "methodA")
# Let's verify it doesn't exist anymore.
# Both of these should throw AttributeError
# Check methodB still remains.

Fun times. The best way to become boring is to say everything.