Object Orientation

 < Day Day Up > 

After having read this far, you should not be surprised to hear that Python's object orientation is flexible and likely to surprise you if you have been using C-like languages for several years.

The best way to learn Python OOP is to just do it. So, here is a basic script that defines a class, creates an object of that class, and calls a function:

 class dog(object):     def bark(self):         print "Woof!" fluffy = dog() fluffy.bark() 

Defining a class starts, predictably, with the class keyword followed by the name of the class you are defining and a colon. The contents of that class need to be indented one level so Python knows where it stops. Note that the object inside parentheses is there for object inheritance, which is discussed later. For now, the least you need to know is that, if your new class is not based on an existing class, you should put object inside parentheses as shown in the previous code.

Functions inside classes work in much the same way as normal functions do (although they are usually called methods) , with the main difference being that they should all take at least one parameter, usually called self. This parameter is filled with the name of the object the function was called on, and you need to use it explicitly.

Creating an instance of a class is done by assignment. You do not need any new keyword, as in some other languages you just provide empty parentheses. Calling a function of that object is done using a period, the name of the class to call, with any parameters being passed inside parentheses.

The previous example is very basic and just prints Woof! The sole function requires no parameters, and there is no class inheritance. Let's make it a bit more complicated.

Class and Object Variables

Each object has its own set of functions and variables, and you can manipulate those variables independently of objects of the same type. Additionally, some class variables are set to a default value for all classes and can also be manipulated globally.

This script demonstrates two objects of the dog class being created, each with its own name:

 class dog(object):     name = "Lassie"     def bark(self):         print self.name + " says 'Woof!'"     def setName(self, name):         self.name = name fluffy = dog() fluffy.bark() poppy = dog() poppy.setName("Poppy") poppy.bark() 

That outputs the following:

 Lassie says 'Woof!' Poppy says 'Woof!' 

There, each dog starts with the name Lassie, but it gets customized. Keep in mind that Python assigns by reference by default, meaning each object has a reference to the class's name variable, and as we assign that with the setName() method, that reference is lost. What this means is that any references we do not change can be manipulated globally. Thus, if we change a class's variable, it also changes in all instances of that class that have not set their own value for that variable. For example:

 class dog(object):     name = "Lassie"     color = "brown" fluffy = dog() poppy = dog() print fluffy.color dog.color = "black" print poppy.color fluffy.color = "yellow" print fluffy.color print poppy.color 

So, the default color of dogs is brown both the fluffy and poppy dog objects start off as brown. Then, using dog.color, we set the default color to be black, and because neither of the two objects has set its own color value, they are updated to be black. The third to last line uses poppy.color to set a custom color value for the poppy object poppy becomes yellow, while fluffy and the dog class in general remain black.

Constructors and Destructors

To help you automate the creation and deletion of objects, you can easily override two default methods: __init__ and __del__. These are the methods called by Python when a class is being instantiated and freed, known as the constructor and destructor, respectively.

Having a custom constructor is great for when you need to accept a set of parameters for each object being created. For example, you might want each dog to have its own name on creation, and you could implement that with this code:

 class dog(object):     def __init__(self, name):         self.name = name fluffy = dog("Fluffy") print fluffy.name 

If you do not provide a name parameter when creating the dog object, Python reports an error and stops. You can, of course, ask for as many constructor parameters as you want, although it is usually better to ask only for the ones you need and have other functions to fill in the rest.

On the other side of things is the destructor method, which allows you to have more control over what happens when an object is destroyed. Using the two, we can show the life cycle of an object by printing messages when it is created and deleted:

 class dog(object):     def __init__(self, name):         self.name = name         print self.name + " is alive!"     def __del__(self):         print self.name + " is no more!" fluffy = dog("Fluffy") 

The destructor is there to give you the chance to free up resources allocated to the object or perhaps log something to a file.

Class Inheritance

Python allows you to reuse your code by inheriting one class from one or more others. For example, lions, tigers, and bears are all mammals and so share a number of similar properties. In that scenario, you would not want to have to copy and paste functions between them; it would be smarter (and easier!) to have a mammal class that defines all the shared functionality and then inherit each animal from that.

Consider the following code:

 class car(object):     color = "black"     speed = 0     def accelerateTo(self, speed):         self.speed = speed     def setColor(self, color):         self.color = color mycar = car() print mycar.color 

That creates a car class with a default color and also provides a setColor() function so people can change their own colors. Now, what do you drive to work? Is it a car? Sure it is, but chances are it is a Ford, or a Dodge, or a Jeep, or some other make you don't get cars without a make. On the other hand, you do not want to have to define a class Ford, give it the methods accelerateTo(), setColor(), and however many other methods a basic car has and then do exactly the same thing for Ferrari, Nissan, and so on.

The solution is to use inheritance: Define a car class that contains all the shared functions and variables of all the makes and then inherit from that. In Python, you do this by putting the name of the class from which to inherit inside parentheses in the class declaration, like this:

 class car(object):     color = "black"     speed = 0     def accelerateTo(self, speed):         self.speed = speed     def setColor(self, color):         self.color = color class ford(car): pass class nissan(car): pass mycar = ford() print mycar.color 

The pass directive is an empty statement it means our class contains nothing new. However, because the ford and nissan classes inherit from the car class, they get color, speed, accelerateTo(), and setColor() provided by their parent class. Note that we do not need object after the classnames for ford and nissan because they are inherited from an existing class: car. This is not a strict requirement. Python 2.2 introduced these "new-style" classes, and they are recommended for use, but you can just use class car:. That said, those old-style ("classic") classes will be removed from the language in the future, so you might as well use the (object).

By default, Python gives you all the methods the parent class has, but you can override that by providing new implementations for the classes that need them. For example:

 class modelt(car):     def setColor(self, color):         print "Sorry, Model Ts only come in black!" myford = ford() ford.setColor("green") mycar = modelt() mycar.setColor("green") 

The first car is created as a Ford, so setColor() will work fine because it uses the method from the car class. However, the second car is created as a Model T, which has its own setColor() method, so the call will fail.

This provides an interesting scenario: What do you do if you have overridden a method and yet want to call the parent's method also? If, for example, changing the color of a Model T was allowed but just cost extra, we would want to print a message saying, "You owe $50 more," but then change the color. To do this, we need to use the class object from which our current class is inherited car in this example. Here's an example:

 class modelt(car):     def setColor(self, color):         print "You owe $50 more"         car.setColor(self, color) mycar = modelt() mycar.setColor("green") print mycar.color 

That prints the message and then changes the color of the car.

Multiple Inheritance

You can inherit as many classes as you need, building up functionality as you go. For example, you could have a class animalia, a subclass chordata, a sub-subclass mammalia, and a sub-sub-subclass homosapiens. Each one is more specific than its parent. However, an interesting addition in Python is the ability to have multiple inheritance to take functionality from two classes simultaneously.

Again, this is best shown in code:

 class car(object):     def drive(self):         print "We're driving..." class timemachine(object):     def timeTravel(self):         print "Traveling through time..." class delorian(car,timemachine): pass mydelorian = delorian() mydelorian.drive() mydelorian.timeTravel() 

In that example, we have a class car and a class timemachine. Both work by themselves, so you can have a car and drive around in it or a time machine and travel through time with it. However, we also have a delorian class that inherits from car and timemachine. As you can see, it is able to call both drive() (inherited from car) and timeTravel() (inherited from timemachine).

This introduces another interesting problem: What happens if both car and timemachine have a refuel() function? The answer is that Python picks the correct function to use based on the order in which you listed the parent classes. In the previous code, we use class delorian(car,timemachine), which means "inherit from car and then from timemachine." As a result, if both classes had a refuel() function, Python would pick car.refuel().

This situation becomes more complex when further inheritance is involved. That is, if car inherits its refuel() method from vehicle, Python still chooses it. What happens behind the scenes is that Python picks the first class you inherited from and searches it and all its parent classes for a matching method call. If it finds none, it goes to the next class and checks it and its parents. This process repeats until it finds a class that has the required method.

     < Day Day Up > 


    Red Hat Fedora 4 Unleashed
    Red Hat Fedora 4 Unleashed
    ISBN: 0672327929
    EAN: 2147483647
    Year: 2006
    Pages: 361

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net