Learning Python Programming - Part 6 - Classes in depth
Welcome to the 6th part of an ongoing series, Learning Python!
Today I will be going over classes more thoroughly.
What are classes?
Classes are probably the most powerful tool in programming. Classes contain a blueprint of an object. As with a blueprint, you can use it over and over to make similar objects.
I love making classes. They make programming so much simpler; to the point that it's only half programming and half scripting.
How do we start with a class?
class Dog:
def __init__(self):
pass
In this class definition, Dog can be any variable name, but it is common practice to capitalize the first letter and use only letters. Parenthesis after Dog are optional, and inside of them are where you would put another class object to inherit another class. The __init__ method is used to set class specific variables with its arguments and is generally used with every class you make, as that is one of the main advantages of classes.
Variables
Classes have their own variables. Some that are class specific, and others that are object specific.
Class specific
The class specific variables are shared by every object in that class and they can be changed on a class scale or on an individual scale. Class specific variables are defined above the __init__ method like this:
class Example:
class_specific_variable = "I'm shared by every Example object"
This can be related to the assigning of "global" variables, or the variables you define by themselves.
When you change this variable on a class level, every object of this class will be changed. Using the code below, I will show some examples.
class Dog:
says = "bark"
fido = Dog()
pupper = Dog()
Changing the variable at the class level:
Dog.says = "yip"
#fido.says = "yip"
# pupper.says = "yip"
Changing the variable at the object level:
fido.says = "yip"
# fido.says = "yip"
# pupper.says = "bark"
These class variables can be very helpful in making a default variable for every member of the class.
Object specific
The object specific variables can hold different values for every class instance and can only be changed on an individual scale. These variables are defined in the __init__ method and are defined with the prefix self.
class Example:
def __init__(self):
self.object_specific_variable = "I'm object specific"
The self prefix refers to the object in question and is used to denote that this variable can be specific to each object.
Self
The self prefix and the self variable are used in classes when referencing the object in question. Using the self prefix is just like using a class object name. Using the self variable is referencing the object in context. If you were to make a class that has a method to return the variable self, it would return the class object and the address from the stack proving that self points to the object in question. Here's the code for that proof if you'd like:
class Name:
def returnself(self):
return self
var = Name()
print(var.returnself())
Why do class methods have to have the first argument be self?
Class methods need the first argument to be self, so that they can use the object specific variables. (Not to say they can use class specific variables without it, because those need the self prefix also.) Also, they need it because when you call a class method you use the class object as a pointer to the class. That object doesn't get forgotten about, it goes into the first argument slot.
Inheritance
Classes are very powerful, but what if a class could be an extension of another class? That's exactly what inheritance is. With inheritance, you can make a sub-class of another class (which is referred to as a super-class) that will contain all the methods, class specific variables, and run the __init__ method from that super-class.
Here I show you inheritance with some aptly named classes:
class Super:
class_var = 0
class_var2 = 10
def __init__(self):
supers_var = 0
class Sub(Super):
class_var2 = 100
def __init__(self):
pass
In that example the Sub class inherits the Super class.
What will print if we run "print(Sub().class_var)"?
A 0 will be printed because the Sub class inherited the variable definition.
The Sub class can also overwrite anything inherited from the Super class by defining what you want to overwrite in the Sub class.
What would print if we run "print(Sub().class_var2)"?
A 100 will be printed because the Sub class overwrote the Super's 10.
What would print if we run "print(Sub().supers_var)"?
A 0 will be printed because the Super's init method is run when it is inherited.
What if I want to inherit from multiple classes?
Why not? Just add a comma in the super list to inherit from more than one super class.
class Sub(Super0,Super1,Super2):
def __init__(self):
pass
What is inheritance good for?
Inheritance is good to use similarities between classes without rewriting code.
I learn best with examples, so let's check one out.
class WaterVessel:
on_water = True
class Boat(WaterVessel):
floats = True
class Submarine(Boat):
in_water = True
sinks = True
class Battleship(Boat):
has_guns = True
class Aircraft:
in_air = True
on_land = True
flies = True
class FloatPlane(Aircraft, Boat):
on_land = False
What does each class hold?
WaterVessel:
- on_water
Boat:
- on_water
- floats
Submarine:
- on_water
- floats
- in_water
- sinks
Battleship:
- on_water
- floats
- has_guns
Aircraft:
- in_air
- on_land
- flies
FloatPlane:
- on_water
- floats
- in_air
- flies
- on_land = False
As you can see in this example, the FloatPlane is both a WaterVessel and an Aircraft, thusly it has all the corresponding variables and it overwrites the value on_land that Aircraft gives it because a FloatPlane can't land on land.
Inheritance is pretty cool and very useful too.
Classes with one object
Classes are very useful to make objects that can have their own values/variables. You can even make classes that will only have one object; this can be really helpful to make something that contains lots of values of different types with a very readable interface.