Having a custom constructor is great 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 for only the ones you need and have other functions 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, you 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.
Python allows you to reuse your code by inheriting one class from one or more others. For example, cars, trucks, and motorbikes are all vehicles, 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 vehicle class that defines all the shared functionality and then inherit each vehicle 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
This creates a car
class with a default color and also provides a setColor()
function so that 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 the 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 you do not need object
after the classnames for ford
and nissan
because they are inherited from an existing class: car
.
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 come only in black!"
myford = ford()
ford.setColor("green")
mycar = modelt()
mycar.setColor("green")
The first car is created as a Ford, so setColor()
works 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, you would want to print a message saying, "You owe $50 more," but then change the color. To do this, you need to use the class object from which the 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.
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 capability 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, you can see 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, there is also 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. The previous code used 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 from which you inherited 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.
Читать дальше