Introduction

By now, you should be familiar with the way basic classes work in Python. If classes were just what you've seen, they'd be fairly rigid and not all that useful.

Thankfully, classes are much more than just that. They are designed to be much more adaptable and can take in information to shape the way they look initially. Not every car starts off exactly the same, and neither should classes. After all, how awful would it be if every car was an orange 71' Ford Pinto? That's not a good situation.

Writing A Class

Start off by setting up a class like the one in the last guide. This class will evolve over the course of this guide. It will move from being a rigid, photocopy-like, situation to a template that can generate multiple unique objects within the outline of the class.

Write the first line of the class, defining it as a class and naming it. This guide is going to stick with the car analogy from before. Don't forget to pass your class object so that it extends the base object class.
class Car(object):
Below that, indent and create your variables. Usually, class variables are grouped near the top of the class and the methods are kept below. It's not strictly mandatory, but it helps to keep the code neat. Only create variables for make, model, year, mileage, and color. There's no point in building a super detailed class.
make = "Ford"
model = "Pinto"
year = "1971"
mileage = "253812"
color = "orange"
At this point, you can test out your variables to make sure that your class is working properly. Create and object, and try to print out your car's model. Then, reassign the model variable, and print it out again.
mycar = Car()
print("My car is a %s" % mycar.model)
mycar.model = "Mustang"
print("My car is a %s" % mycar.model)
That's an upgrade, but your car still can't do anything. It's time to add a method. Create a new method in your class called move_forward that accepts a variable called, "speed." Then, have it print out the model of your car and how fast it's going. Don't forget to include self.
def move_forward(self, speed):
	print("Your %s is moving forward at %s" % (self.model, speed))
Test that out with your class.
mycar.move_forward("25mph")
Everything should be going well, and your car should be running.

Creating A Constructor

Changing variables after an object is created is clunky and inefficient. Not only do you waste time, but it bloats up your code too. This is especially true if you are creating multiple instances of the same class and altering each one.

There is a concept in Object Oriented Programming called a constructor. Constructors are special methods that allow an object to take arguments when it is created and automatically carry out actions. They are usually used for assigning variables at the time an object is instantiated.

In the case of Python, you create a constructor like you would any other method, using dev, but every constructor has the same name, __init__. You can think of __init__ as being short for initialize because it is run when the object is initialized.

Create a constructor for your car that takes in all of the variables as parameters and assigns them to instance variables with self. An instance variable is just a variable that exists in a specific instance of an object.
def __init__(self, make, model, year, mileage, color):
	self.make = make
    self.model = model
    self.year = year
    self.mileage = mileage
    self.color = color
Make sure to delete the old variable declarations. You don't need them anymore.

Using The Constructor

Run your code again, and see what happens. If you got an error, you're doing it right. Now, every time you create an instance of Car(), you need to pass it enough arguments to match the parameters that you specified.

Go back and modify the instantiation of the mycar to pass it the required arguments.
mycar = Car('Dodge', 'Challenger', '2017', 1500, 'black')
Run your code again. Everything should work, and you should have a different car running.

As you already saw, this isn't the perfect system. What if you still want a default template, so you don't have to pass in every argument? You can absolutely do that too. You just have to set every parameter in your constructor equal to the value that you want to be its default.
def __init__(self, make = 'Ford', model = 'Pinto', year = '1971', mileage = '253812',      color = 'orange'):
    self.make = make
    self.model = model
    self.year = year
    self.mileage = mileage
    self.color = color
If you create a new instance of Car() and don't pass it anything, it will create your good old Ford Pinto again. Try comparing them side by side to see the difference.
mycar = Car()
mynewcar = Car('Dodge', 'Challenger', '2017', 1500, 'black')

mycar.move_forward('25mph')
mynewcar.move_forward('85mph')

Closing Thoughts

It would suck if every car was a 71' Ford Pinto. It's the same thing for objects. If you had to create a new class as a template for every variation of an object, there really wouldn't be any value in Object Oriented Programming. Constructors allow classes to be much more fluid and adaptable. You can create as many different new instances of an object as you need from the same class without ever having to go back and change anything.

Practice making a new class and adding a constructor, then using that class a bit in your script.

Exercises

  1. Create a new class called "Computer."
  2. Create a constructor for "Computer" that takes four variables.
  3. Print out one of your variables. Reassign its value, and print it again.
  4. Make a method that uses at least two of your variables.
  5. Implement a constructor for "Computer" that accepts all of your variables.
  6. Create a new instance of "Computer" and pass it the correct arguments.
  7. Run your method on the new instance of "Computer."
  8. Add default values to the "Computer" constructor.
  9. Create an empty instance of "Computer."
  10. Run your method on the new empty instance.