Classes
Precap
Classes are a named mix of variables and functions. They are used to instantiate (= create) objects. The concept behind it is also called object orientated programming (OOP) and though it might not be easy to understand fully at first sight, it is very widespread and useful. Actually almost everything within Python is defined by a class.
While writing a program, even simple projects might require a lot of code. Usually there are also many solutions to a single task. While comparing different solutions some of the criteria might be
Does the code repeat itself a lot? Less repetitions are preferred.
Is it maintainable? Keeping statements that are related to each other close together is preferred.
Imagine a program, that involves storing the dimensions of rectangles and calculating their areas. There are quite a few different approaches thinkable, but classes are the best solution.
Two rectangles
Version 1: Using a separate variables for everything
This version is the simplest one. It uses 6 lines of code (+ 5 for the print statements) and 6 variables appearing 16 times. If task would require 100 rectangles the code for this version would be very long and thus hard to read and maintain.
Version 2: Using an array to combine width & height into one variable per rectangle
This version uses 4 lines of code (2 less than version 1), but is hard to read because statements like r1 = [10, 20] are not self-explanatory at all, though this could be fixed with some comments in the code.
Version 3a: Using dictionaries instead of arrays
This version uses the same amount of lines like version 2. The circumstance that the statements are longer is not a disadvantage here since they are more self-explanatory.
Version 3b: Using the double asterisk ** to unpack the dictionary and shorten the lines in the print statements
Unpacking dictionaries (= preceding the identifier with a double asterisk **) is a very short and convienient way to in fact write .format(width=r1['width'], height=r1['height'], area=r1['area']).
Version 4a: Using a dictionaries but replacing the calculation with a function
This version adds two lines in comparison to version 3a and 3b, but has the benefit that if the area calculation would have to be changed, it needs to be changed only once.
Version 4b: Using the rectangle as function argument instead of its width and height
This version has a bit shorter lines, since the function here takes the dictionary and adds directly the item 'area' to it without returning a result using the return keyword.
Two rectangles using a class
The only way to further improve the preceeding examples is to use classes. Classes are used to instantiate (= create) objects. The relation can also be thought of as a blueprint of a house (= the class definition) and a built house (= the instatiated object).
Basic pseudo code of a class
The basic definition of a class starts with the class keyword followed by an identifier as class name, which usually starts with a capital letter (by convention). Then, with the indentation defined as part of the class, there is a series of function definitions, where the first one uses the predefined name __init__() and all functions use self as their first argument.
NOTE: The pseudo code above will throw an error and syntax coloring also fails.
The following mechanisms are important to comprehend:
object = BasicClass()instantiates (= creates) an object from a class.The
__init__()function will be called for each object when it is instantiated.Instance variables for an object can be accessed by
object_name.instance_variable.Instance functions for an object can be accessed by
object_name.instance_function(argument_2, argument_3, ...).The first argument
selfis used as a placeholder within the class definition.Multiple objects of a class can be instatiated.
Version 5a: Using a class for the rectangle's variables and functions
The indented code within the class definition in this examples consists of two instance function definitions def __init__(self, w, h): and def area(self):. Within the first one two instance variables self.width and self.height
Special function name init()
The first function in the example with the special name __init__(self, w, h): will be called once (and only once) for each object when it is created. It is intended to be used for tasks that initally setup e.g. variables.
The function name is predefined and cannot be changed.
Special argument self
The self argument works as placeholder for an object name within the class definition. It is used to define instance variables by preceding them with self. and it is supplied as first positional argument to each function definition to be able to access any instance variables or instance functions.
The name self is only a convention and it could actually be replaced by any other valid identifer, but since this would be unexpected and confusing is highly not recommended (other programming languages use eg me or this).
Instance variables
Instance variables are preceded with self. and not removed from memory after a function call is finished (and are thus have a longer lifetime than local variables).
Version 5b: Same as 5a but adding a the function as_dict(self) to be able to use dictionary unpacking