Quick Notes
Python is an object-oriented language. It supports all the usual functionality of such languages such as classes, inheritance, and polymorphism. If you are not familiar with object-oriented programming (or scripting), it basically means it is easy to create modular, reusable bits of code, which are called objects. We have already been dealing with objects such as string objects and list objects. Below is an example of creating a string object and calling its methods.
x = "happy"
x.capitalize() # returns Happy
x.endswith("ppy") # returns True
x.replace("py", "hazard") # returns "haphazard"
x.find( "y" ) # returns 4
You are free to use Python without using any of its object oriented functionality by just sticking with functions and groups of statements as we have been doing throughout these notes. However, if you would like to create larger scale applications and systems, I recommend learning more about object oriented programming. The Maya programming API and pymel, the popular Maya commands replacement module, are built upon the notions of object oriented programming so if you want to use API functionality or pymel in your scripts, you should understand the principles of OOP.
Classes
Classes are the basic building blocks of object oriented programming. With classes, we can create independent instances of a common object. It is kind of like duplicating a cube a few times. They are all cubes, but they have their own independent attributes.
class shape:
def __init__(self, name):
self.name = name
def printMyself(self):
print 'I am a shape named %s.' % self.name
>>> shape1 = shape(name='myFirstShape.')
>>> shape2 = shape(name='mySecondShape.')
>>> shape1.printMyself()
I am a shape named myFirstshape.
>>>shape2.printMyself ()
I am a shape named mySecondShape.
The above example shows a simple class that contains one data member (name), and two functions. Functions that begin with a double underscore usually have a special meaning in Python. The __init__ function of a class is a special function called a constructor. It allows us to construct a new instance of an object. In the example, we create two independent instances of a shape object: shape1 and shape2. Each of these instances contains its own copy of the name attribute defined in the class definition. In the shape1 instance, the value of name is “myFirstShape”. In the shape2 instance, the value of name is “mySecondShape”. Notice we don’t pass in any value for the self argument. We don’t pass in any value for the self argument because the self argument refers to the particular instance of a class.
The first argument in all class methods (functions) should be the self argument. The self argument is used to represent the current instance of that class. You can see in the above example when we call the printMyself method of each instance, it prints the name stored in each separate instance. So objects are containers that hold their own copies of data defined in their class definition.
Inheritance and Polymorphism
Inheritance and polymorphism are OOP constructs that let us build off of existing functionality. Say we wanted to add additional functionality to the previous shape class but we don’t want to change it because many other scripts reference that original class. We can create a new class that inherits the functionality of that class and then we can use that inherited class to build additional functionality:
class polyCube(shape):
def __init__(self, name, length, width, height):
# Call the constructor of the inherited class
shape.__init__(name)
# Store the data associated with this inherited class
self.length = length
self.width = width
self.height = height
def printMyself(self):
shape.printMyself(self)
print 'I am also a cube with dimensions %.2f, %.2f, %.2f.' % (length, width, height)
class polySphere(shape):
def __init__(self, name, radius):
# Call the constructor of the inherited class
shape.__init__(name)
# Store the data associated with this inherited class
self.radius = radius
def printMyself(self):
shape.printMyself(self)
print 'I am also a sphere with a radius of %.2f.' % radius
>>> cube1 = polyCube('firstCube', 2.0, 1.0, 3.0)
>>> cube2 = polyCube('secondCube', 3.0, 3.0, 3.0)
>>> sphere1 = polySphere('firstSphere', 2.2)
>>> sphere2 = polySphere('secondSphere', 2.5)
>>> shape1 = shape('myShape')
>>> cube1.printMyself()
I am a shape named firstCube.
I am also a cube with dimensions 2.00, 1.00, 2.00.
>>> cube2.printMyself()
I am a shape named secondCube.
I am also a cube with dimensions 3.00, 3.00, 3.00.
>>> sphere1.printMyself()
I am a shape named firstSphere.
I am also a sphere with a radius of 2.20.
>>> sphere2.printMyself()
I am a shape named secondSphere.
I am also a sphere with a radius of 2.50.
In the above example, we create two new classes, polyCube and polySphere, that inherit from the base class, shape. The two new classes will have all the data and methods associated with the shape base class. When we call the constructor method, __init__, of polyCube and polySphere, we still want to use the functionality of the constructor of its super class, shape. We can do this by calling the super class constructor explicitly with shape.__init__(self). This will set the name variable since the name variable is inherited from the shape class. Notice when we call the constructor of shape inside of the inherited classes, we pass in the self argument. We do this because we’ve already created the instance by calling the polyCube or polySphere constructors. By passing in the self argument to the shape constructor, we are telling Python that we do not want to create a new instance, rather we would like to use the current instance that self refers to. The second method contains the added functionality of our new class. The method name is the same as the method name in the super class, character. However, when we call the method with cube1.printMyself(), Python knows to use the method in polyCube and not the method from shape. This is called polymorphism. It allows us to replace, change, or add functionality to existing classes. By creating these hierarchies of objects, you can create pretty complex systems in neat, reusable classes that will keep your code clean and maintainable.
The previous example is an extremely simplified version of Maya’s architecture. Nodes inherit off of other nodes to build a complex hierarchy. Below is part of Maya’s object oriented node hierarchy:

Figure 12 - Maya Inheritance Hierarchy

