Object-oriented programming is one of the
most effective approaches to writing software. In object-oriented programming you
write classes that represent real-world things
and situations, and you create objects based on these
classes. When you write a class, you define the general
behavior that a whole category of objects can have.
When you create individual objects from the class, each object is automatically equipped with the general behavior; you can then give each object
whatever unique traits you desire. You’ll be amazed how well real-world
situations can be modeled with object-oriented programming.
Making an object from a class is called instantiation, and you work with
instances of a class. Today you’ll write classes and create instances
of those classes. You’ll specify the kind of information that can be stored in
instances, and you’ll define actions that can be taken with these instances.
You’ll also write classes that extend the functionality of existing classes, so similar classes can share code efficiently. You’ll store your classes in modules and import classes written by other programmers into your own program files.
Creating and Using a Class
You can model almost anything using classes. Let’s start by writing a simple
class, Dog, that represents a dog—not one dog in particular, but any dog.
What do we know about most pet dogs? Well, they all have a name and age.
We also know that most dogs sit and roll over. Those two pieces of information (name and age) and those two behaviors (sit and roll over) will go
in our Dog class because they’re common to most dogs. This class will tell
Python how to make an object representing a dog. After our class is written,
we’ll use it to make individual instances, each of which represents one specific dog.
Creating the Dog Class
Each instance created from the Dog class will store a name and an age, and
we’ll give each dog the ability to sit() and roll_over():
class Dog():
"""A simple attempt to model a dog."""
def __init__(self, name, age):
"""Initialize name and age attributes."""
self.name = name
self.age = age
def sit(self):
"""Simulate a dog sitting in response to a command."""
print(self.name.title() + " is now sitting.")
def roll_over(self):
"""Simulate rolling over in response to a command."""
print(self.name.title() + " rolled over!")
There’s a lot to notice here, but don’t worry. You’ll see this structure
throughout this chapter and have lots of time to get used to it. First we
define a class called Dog. By convention, capitalized names refer to classes
in Python. The parentheses in the class definition are empty because we’re
creating this class from scratch.
The __init__() Method
A function that’s part of a class is a method. Everything you learned about
functions applies to methods as well; the only practical difference for now is
the way we’ll call methods. The __init__() method is a special method
Python runs automatically whenever we create a new instance based on the
Dog class. This method has two leading underscores and two trailing underscores, a convention that helps prevent Python’s default method names
from conflicting with your method names.
We define the __init__() method to have three parameters: self, name,
and age. The self parameter is required in the method definition, and it
must come first before the other parameters. It must be included in the definition because when Python calls this __init__() method later (to create an
instance of Dog), the method call will automatically pass the self argument.
Every method call associated with a class automatically passes self, which
is a reference to the instance itself; it gives the individual instance access to
the attributes and methods in the class. When we make an instance of Dog,
Python will call the __init__() method from the Dog class. We’ll pass Dog()
a name and an age as arguments; self is passed automatically, so we don’t
need to pass it. Whenever we want to make an instance from the Dog class,
we’ll provide values for only the last two parameters, name and age.
The two variables defined inside __init__() method each have the prefix self. Any variable
prefixed with self is available to every method in the class, and we’ll also be
able to access these variables through any instance created from the class.
self.name = name takes the value stored in the parameter name and stores it
in the variable name, which is then attached to the instance being created.
The same process happens with self.age = age. Variables that are accessible
through instances like this are called attributes.
The Dog class has two other methods defined: sit() and roll_over() y.
Because these methods don’t need additional information like a name
or age, we just define them to have one parameter, self. The instances
we create later will have access to these methods. In other words, they’ll
be able to sit and roll over. For now, sit() and roll_over() don’t do much.
They simply print a message saying the dog is sitting or rolling over. But
the concept can be extended to realistic situations: if this class were part
of an actual computer game, these methods would contain code to make
an animated dog sit and roll over. If this class was written to control a
robot, these methods would direct movements that cause a dog robot to
sit and roll over.
Making an Instance from a Class
Think of a class as a set of instructions for how to make an instance. The
class Dog is a set of instructions that tells Python how to make individual
instances representing specific dogs.
Let’s make an instance representing a specific dog:
class Dog():
--snip--
my_dog = Dog('willie', 6)
print("My dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old.")
The Dog class we’re using here is the one we just wrote in the previous
example. Here, we tell Python to create a dog whose name is 'willie' and
whose age is 6. When Python reads this line, it calls the __init__() method
in Dog with the arguments 'willie' and 6. The __init__() method creates an
instance representing this particular dog and sets the name and age attributes
using the values we provided. The __init__() method has no explicit return
statement, but Python automatically returns an instance representing this
dog. We store that instance in the variable my_dog. The naming convention is
helpful here: we can usually assume that a capitalized name like Dog refers
to a class, and a lowercase name like my_dog refers to a single instance created from a class.
Accessing Attributes
To access the attributes of an instance, you use dot notation. We access
the value of my_dog’s attribute name by writing:
print( my_dog.name) gives Willie.
Calling Methods
After we create an instance from the class Dog, we can use dot notation to
call any method defined in Dog. Let’s make our dog sit and roll over:
class Dog():
--snip--
my_dog = Dog('willie', 6)
my_dog.sit()
my_dog.roll_over()
Output
Willie is now sitting.
Willie rolled over!
To call a method, give the name of the instance (in this case, my_dog)
and the method you want to call, separated by a dot. When Python reads
my_dog.sit(), it looks for the method sit() in the class Dog and runs that
code. Python interprets the line my_dog.roll_over() in the same way.
Creating Multiple Instances
You can create as many instances from a class as you need. Let’s create a
second dog called your_dog:
class Dog():
--snip--
my_dog = Dog('willie', 6)
your_dog = Dog('lucy', 3)
print("My dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old.")
my_dog.sit()
print("\nYour dog's name is " + your_dog.name.title() + ".")
print("Your dog is " + str(your_dog.age) + " years old.")
your_dog.sit()
Output
My dog's name is Willie.
My dog is 6 years old.
Willie is now sitting.
Your dog's name is Lucy.
Your dog is 3 years old.
Lucy is now sitting.
In this example we create a dog named Willie and a dog named Lucy.
Each dog is a separate instance with its own set of attributes, capable of the
same set of actions.
Working with Classes and Instances
You can use classes to represent many real-world situations. Once you write
a class, you’ll spend most of your time working with instances created from
that class. One of the first tasks you’ll want to do is modify the attributes
associated with a particular instance. You can modify the attributes of an
instance directly or write methods that update attributes in specific ways.
The Car Class
Let’s write a new class representing a car. Our class will store information
about the kind of car we’re working with, and it will have a method that
summarizes this information:
class Car():
"""A simple attempt to represent a car."""
def __init__(self, make, model, year): """Initialize attributes to describe a car."""
self.make = make
self.model = model
self.year = year
def get_descriptive_name(self):
"""Return a neatly formatted descriptive name."""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
Output
2016 Audi A4
Setting a Default Value for an Attribute
Every attribute in a class needs an initial value, even if that value is 0 or an
empty string. In some cases, such as when setting a default value, it makes
sense to specify this initial value in the body of the __init__() method; if
you do this for an attribute, you don’t have to include a parameter for that
attribute.
Let’s add an attribute called odometer_reading that always starts with a
value of 0. We’ll also add a method read_odometer() that helps us read each
car’s odometer:
class Car():
"""A simple attempt to represent a car."""
def __init__(self, make, model, year): """Initialize attributes to describe a car."""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""Return a neatly formatted descriptive name."""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
def read_odometer(self):
"""Print a statement showing the car's mileage."""
print("This car has " + str(self.odometer_reading) + " miles on it.")
return long_name.title()
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
Output
2016 Audi A4
This car has 0 miles on it.
Modifying Attribute Values
You can change an attribute’s value in three ways: you can change the value
directly through an instance, set the value through a method, or increment
the value (add a certain amount to it) through a method. Let’s look at each
of these approaches.
Modifying an Attribute’s Value Directly
The simplest way to modify the value of an attribute is to access the attribute directly through an instance. Here we set the odometer reading to 23
directly:
class Car():
--snip--
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
Output
2016 Audi A4
This car has 23 miles on it.
Modifying an Attribute’s Value Through a Method
It can be helpful to have methods that update certain attributes for you.
Instead of accessing the attribute directly, you pass the new value to a
method that handles the updating internally.
Here’s an example showing a method called update_odometer():
def update_odometer(self, mileage):
"""Set the odometer reading to the given value."""
self.odometer_reading = mileage
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(23)
my_new_car.read_odometer()
Output
2016 Audi A4
This car has 23 miles on it.
Incrementing an Attribute’s Value Through a Method
Sometimes you’ll want to increment an attribute’s value by a certain
amount rather than set an entirely new value. Say we buy a used car and
put 100 miles on it between the time we buy it and the time we register it.
Here’s a method that allows us to pass this incremental amount and add
that value to the odometer reading:
def update_odometer(self, mileage):
--snip--
def increment_odometer(self, miles):
"""Add the given amount to the odometer reading."""
self.odometer_reading += miles
my_used_car = Car('subaru', 'outback', 2013)
print(my_used_car.get_descriptive_name())
my_used_car.update_odometer(23500)
my_used_car.read_odometer()
my_used_car.increment_odometer(100)
my_used_car.read_odometer()
Output
2013 Subaru Outback
This car has 23500 miles on it.
This car has 23600 miles on it.
Inheritance
You don’t always have to start from scratch when writing a class. If the class
you’re writing is a specialized version of another class you wrote, you can
use inheritance. When one class inherits from another, it automatically takes
on all the attributes and methods of the first class. The original class is
called the parent class, and the new class is the child class. The child class
inherits every attribute and method from its parent class but is also free to
define new attributes and methods of its own.
The __init__() Method for a Child Class
The first task Python has when creating an instance from a child class is to
assign values to all attributes in the parent class. To do this, the __init__()
method for a child class needs help from its parent class.
As an example, let’s model an electric car. An electric car is just a specific kind of car, so we can base our new ElectricCar class on the Car class
we wrote earlier. Then we’ll only have to write code for the attributes and
behavior specific to electric cars.
class Car():
"""A simple attempt to represent a car."""
def __init__(self, make, model, year): """Initialize attributes to describe a car."""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""Return a neatly formatted descriptive name."""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
def read_odometer(self):
"""Print a statement showing the car's mileage."""
print("This car has " + str(self.odometer_reading) + " miles on it.")
return long_name.title()
def update_odometer(self, mileage):
"""Set the odometer reading to the given value."""
self.odometer_reading = mileage
def increment_odometer(self, miles):
"""Add the given amount to the odometer reading."""
self.odometer_reading += miles
class ElectricCar(Car):
"""Represent aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year):
"""Initialize attributes of the parent class."""
super().__init__(make, model, year)
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
Output
2016 Tesla Model S
When you create a child class, the parent class
must be part of the current file and must appear before the child class in
the file. The name of the parent
class must be included in parentheses in the definition of the child class.
The super() function is a special function that helps Python make
connections between the parent and child class. This line tells Python to
call the __init__() method from ElectricCar’s parent class, which gives an
ElectricCar instance all the attributes of its parent class. The name super
comes from a convention of calling the parent class a superclass and the
child class a subclass.
Inheritance in Python 2.7
In Python 2.7, inheritance is slightly different. The ElectricCar class would
look like this:
class Car(object):
--snip--
class ElectricCar(Car):
def __init__(self, make, model, year):
super(ElectricCar, self).__init__(make, model, year)
--snip--
Note the two bold lines that are different for two different versions of python. The super() function needs two arguments: a reference to the child
class and the self object. These arguments are necessary to help Python
make proper connections between the parent and child classes. When you
use inheritance in Python 2.7, make sure you define the parent class using
the object syntax as well.
Defining Attributes and Methods for the Child Class
Once you have a child class that inherits from a parent class, you can add
any new attributes and methods necessary to differentiate the child class
from the parent class.
Let’s add an attribute that’s specific to electric cars (a battery, for
example) and a method to report on this attribute. We’ll store the battery
size and write a method that prints a description of the battery:
class Car(object):
--snip--
class ElectricCar(Car):
"""Represent aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year):
"""
Initialize attributes of the parent class.
Then initialize attributes specific to an electric car.
"""
super().__init__(make, model, year)
self.battery_size = 70
def describe_battery(self):
"""Print a statement describing the battery size."""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
Output
2016 Tesla Model S
This car has a 70-kWh battery.
Here, we add a new attribute self.battery_size and set its initial value to,
say, 70. This attribute will be associated with all instances created from the
ElectricCar class but won’t be associated with any instances of Car. We also
add a method called describe_battery() that prints information about the
battery.
Overriding Methods from the Parent Class
You can override any method from the parent class that doesn’t fit what
you’re trying to model with the child class. To do this, you define a method
in the child class with the same name as the method you want to override
in the parent class. Python will disregard the parent class method and only
pay attention to the method you define in the child class.
Say the class Car had a method called fill_gas_tank(). This method is
meaningless for an all-electric vehicle, so you might want to override this
method. Here’s one way to do that:
def ElectricCar(Car):
--snip--
def fill_gas_tank():
"""Electric cars don't have gas tanks."""
print("This car doesn't need a gas tank!")
Now if someone tries to call fill_gas_tank() with an electric car, Python
will ignore the method fill_gas_tank() in Car and run this code instead. When
you use inheritance, you can make your child classes retain what you need
and override anything you don’t need from the parent class.
Instances as Attributes
When modeling something from the real world in code, you may find that
you’re adding more and more detail to a class. You’ll find that you have a
growing list of attributes and methods and that your files are becoming
lengthy. In these situations, you might recognize that part of one class can
be written as a separate class. You can break your large class into smaller
classes that work together.
For example, if we continue adding detail to the ElectricCar class, we
might notice that we’re adding many attributes and methods specific to
the car’s battery. When we see this happening, we can stop and move those
attributes and methods to a separate class called Battery. Then we can use a
Battery instance as an attribute in the ElectricCar class:
class Car():
--snip--
class Battery():
"""A simple attempt to model a battery for an electric car."""
v
def __init__(self, battery_size=70):
"""Initialize the battery's attributes."""
self.battery_size = battery_size
def describe_battery(self):
"""Print a statement describing the battery size."""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
class ElectricCar(Car):
"""Represent aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year):
""" Initialize attributes of the parent class. Then initialize attributes specific to an electric car.""" super().__init__(make, model, year)
self.battery = Battery()
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
Output
2016 Tesla Model S
This car has a 70-kWh battery.
First we define a new class called Battery that doesn’t inherit from any
other class. The method describe_battery() has been moved
to this class now. In the ElectricCar class, we now add an attribute called self.battery. This line tells Python to create a new instance of Battery (with a default size
of 70, because we’re not specifying a value) and store that instance in the
attribute self.battery. This will happen every time the __init__() method
is called; any ElectricCar instance will now have a Battery instance created
automatically.
We create an electric car and store it in the variable my_tesla. When
we want to describe the battery, we need to work through the car’s battery
attribute:
my_tesla.battery.describe_battery()
This line tells Python to look at the instance my_tesla, find its battery
attribute, and call the method describe_battery() that’s associated with the
Battery instance stored in the attribute.
Importing Classes
As you add more functionality to your classes, your files can get long, even
when you use inheritance properly. In keeping with the overall philosophy
of Python, you’ll want to keep your files as uncluttered as possible. To help,
Python lets you store classes in modules and then import the classes you
need into your main program.
Importing a Single Class
Let's keep it straightforward, first let's create a file "car.py" and define our class Car within it. We will later import and use class Car from another file "my_car.py".
car.py
"""A class that can be used to represent a car."""
class Car():
"""A simple attempt to represent a car."""
def __init__(self, make, model, year): """Initialize attributes to describe a car."""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""Return a neatly formatted descriptive name."""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
def read_odometer(self):
"""Print a statement showing the car's mileage."""
print("This car has " + str(self.odometer_reading) + " miles on it.")
return long_name.title()
def update_odometer(self, mileage):
"""Set the odometer reading to the given value."""
self.odometer_reading = mileage
def increment_odometer(self, miles):
"""Add the given amount to the odometer reading."""
self.odometer_reading += miles
my_car.py
from car import Car
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
The import statement tells Python to open the car module and
import the class Car. Now we can use the Car class as if it were defined in
this file. The output is the same as we saw earlier:
Output
2016 Audi A4
This car has 23 miles on it.
Importing classes is an effective way to program. Picture how long
this program file would be if the entire Car class were included. When you
instead move the class to a module and import the module, you still get all
the same functionality, but you keep your main program file clean and easy
to read. You also store most of the logic in separate files; once your classes
work as you want them to, you can leave those files alone and focus on the
higher-level logic of your main program.
Storing Multiple Classes in a Module
You can store as many classes as you need in a single module, although
each class in a module should be related somehow. The classes Battery and
ElectricCar both help represent cars, so you can add both the classes in same module 'car' and later import these classes just like above example.
car.py
class Car():
--snip--
class Battery():
--snip--
class ElectricCar(Car):
--snip--
Importing Multiple Classes from a Module
You can import as many classes as you need into a program file. If we
want to make a regular car and an electric car in the same file, we need
to import both classes, Car and ElectricCar:
my_car.py
from car import Car, ElectricCar
my_beetle = Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name())
my_tesla = ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name())
Output
2016 Volkswagen Beetle
2016 Tesla Roadster
You import multiple classes from a module by separating each class
with a comma. Once you’ve imported the necessary classes, you’re free
to make as many instances of each class as you need.
Importing an Entire Module
You can also import an entire module and then access the classes you need
using dot notation. This approach is simple and results in code that is easy
to read. Because every call that creates an instance of a class includes the
module name, you won’t have naming conflicts with any names used in the
current file.
Here’s what it looks like to import the entire car module and then create
a regular car and an electric car:
import car
my_beetle = car.Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name())
my_tesla = car.ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name())
First we import car module then access the classes we
need through the module_name.class_name syntax.
Importing All Classes from a Module
You can import every class from a module using the following syntax:
from module_name import *
This method is not recommended for two reasons. First, it’s helpful
to be able to read the import statements at the top of a file and get a clear
sense of which classes a program uses. With this approach it’s unclear which
classes you’re using from the module. This approach can also lead to confusion with names in the file. If you accidentally import a class with the same
name as something else in your program file, you can create errors that are
hard to diagnose. I show this here because even though it’s not a recommended approach, you’re likely to see it in other people’s code.
Importing a Module into a Module
Sometimes you’ll want to spread out your classes over several modules
to keep any one file from growing too large and avoid storing unrelated
classes in the same module. When you store your classes in several modules,
you may find that a class in one module depends on a class in another module. When this happens, you can import the required class into the first
module.
For example, let’s store the Car class in one module and the ElectricCar
and Battery classes in a separate module. We’ll make a new module called
electric_car.py and copy
just the Battery and ElectricCar classes into this file:
electric_car.py
"""A set of classes that can be used to represent electric cars."""
from car import Car
class Battery():
--snip--
class ElectricCar(Car):
--snip--
The class ElectricCar needs access to its parent class Car, so we import
Car directly into the module. If we forget this line, Python will raise an
error when we try to make an ElectricCar instance. We also need to update
the Car module so it contains only the Car class:
car.py
"""A class that can be used to represent a car."""
class Car():
--snip--
Now we can import from each module separately and create whatever
kind of car we need:
my_cars.py
from car import Car
from electric_car import ElectricCar
my_beetle = Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name())
my_tesla = ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name())
Output
2016 Volkswagen Beetle
2016 Tesla Roadster
The Python Standard Library
The Python standard library is a set of modules included with every Python
installation. Now that you have a basic understanding of how classes work,
you can start to use modules like these that other programmers have written. You can use any function or class in the standard library by including
a simple import statement at the top of your file. Let’s look at one class,
OrderedDict, from the module collections.
Dictionaries allow you to connect pieces of information, but they don’t
keep track of the order in which you add key-value pairs. If you’re creating
a dictionary and want to keep track of the order in which key-value pairs
are added, you can use the OrderedDict class from the collections module.
Instances of the OrderedDict class behave almost exactly like dictionaries
except they keep track of the order in which key-value pairs are added.
from collections import OrderedDict
favorite_languages = OrderedDict()
favorite_languages['jen'] = 'python'
favorite_languages['sarah'] = 'c'
favorite_languages['edward'] = 'ruby'
favorite_languages['phil'] = 'python'
for name, language in favorite_languages.items():
print(name.title() + "'s favorite language is " +
language.title() + ".")
Output
Jen's favorite language is Python.
Sarah's favorite language is C.
Edward's favorite language is Ruby.
Phil's favorite language is Python.
Here, we begin by importing the OrderedDict class from the module
collections. Then, we create an instance of the OrderedDict class
and store this instance in favorite_languages. Notice there are no curly
brackets; the call to OrderedDict() creates an empty ordered dictionary
for us and stores it in favorite_languages. We then add each name and language to favorite_languages one at a time. Now when we loop through
favorite_languages, we know we’ll always get responses back in the
order they were added.
This is a great class to be aware of because it combines the main benefit
of lists (retaining your original order) with the main feature of dictionaries
(connecting pieces of information). As you begin to model real-world situations that you care about, you’ll probably come across a situation where an
ordered dictionary is exactly what you need. As you learn more about the
standard library, you’ll become familiar with a number of modules like this
that help you handle common situations.
Conclusion
In this blog you learned how to write your own classes. You learned
how to store information in a class using attributes and how to write
methods that give your classes the behavior they need. You learned to
write __init__() methods that create instances from your classes with
exactly the attributes you want. You saw how to modify the attributes of
an instance directly and through methods. You learned that inheritance
can simplify the creation of classes that are related to each other, and you
learned to use instances of one class as attributes in another class to keep
each class simple.
You saw how storing classes in modules and importing classes you need
into the files where they’ll be used can keep your projects organized. You
started learning about the Python standard library, and you saw an example
based on the OrderedDict class from the collections module.
In next blog you’ll learn to work with files so you can save the work
you’ve done in a program and the work you’ve allowed users to do. You’ll
also learn about exceptions, a special Python class designed to help you
respond to errors when they arise.
I am attracted by the info which you have provided in the above post.Bidded Car Plate
ReplyDelete