Python Object Oriented Programming: Classes, Description, and Features

In Python, classes are a fundamental concept. This is the basis of the standard library, the work of most popular programs and the language itself. If you want to become more than just a novice programmer, you must understand the essence and principle of working with classes and objects.

python classes

What are classes

This is the basic software component of OOP. In Python, classes are used to implement new types of objects and are created using a special class statement. Outwardly, they resemble standard built-in data types, such as numbers or sequences. But class objects have a significant difference - support for inheritance.

Object-oriented programming in Python is based entirely on hierarchical class inheritance. This is a universal way to adapt and reuse code. But an object-oriented approach is optional. Python allows only procedural and functional programming without problems.

The main task of classes in Python is to pack data and executable code. They are syntactically similar to def instructions. Like functions, they create their own namespaces that can be called repeatedly from any part of the program. Why then are they needed? Classes are a more powerful and versatile tool. Most of all, their potential is revealed at the time of the creation of new objects.

python class methods

The importance of classes and the principle of inheritance

Each new object has its own namespace, which can be programmed, enter variables and create any functions. And also there are attributes inherited from the class: object.attribute. This is the meaning of OOP.

Thanks to inheritance, a hierarchy tree is created. In practice, this is as follows. When the interpreter encounters the expression object.attribute, it starts looking for the first occurrence of the attribute in the specified class. If the attribute is not found, the interpreter continues the search in all related classes located in the tree above, from left to right.

The search tree includes:

  • superclasses that are at the very top of the hierarchy and implement common behavior;
  • subclasses are below;
  • instances are program elements with inherited behavior.

python objects classes
The image shows the Python class tree. As you can see from the example, Class 2 and 3 are superclasses. At the very bottom are two instances of Instance 1 and 2, in the middle there is a subclass of Class 1. If you write the expression Instance2.w, it will force the interpreter to look for the value of the .w attribute in the following order:

  1. Instance2;
  2. Class1;
  3. Class2;
  4. Class3.

The name .w will be found in the superclass of Class3. In OOP terminology, this means that Instance 2 “inherits” the .w attribute from Class3.

Note that the instances in the drawing inherit only four attributes: .w, .x, .y and .z:

  • For instances of Instance1.x and Instance2.x, the .x attribute will be found in Class 1, where the search will stop because Class 1 is in the tree lower than Class 2.
  • For Instance1.y and Instance2.y, the .y attribute will be found in Class 1, where the search will stop, because this is the only place it appears.
  • For instances of Instance1.z and Instance2.z, the interpreter will find .z in Class 2 because it is located to the left of the tree than Class3.
  • For Instance2.name, the .name attribute will be found in Instance2 without searching the tree.

The penultimate paragraph is the most important. It demonstrates how Class 1 overrides the .x attribute, replacing the .x version of the Class 2 superclass.

Objects, Instances, and Methods

OOP operates with two main concepts: classes and objects. Classes create new types, and class objects in Python are their instances. For example, all integer variables are of the int int data type. In OOP, they are instances of the int class.

Classes are created by instructions, and objects by calls. They can store data and have their own functionality or class methods. In Python, terminology plays an important role. With its help, programmers distinguish independent functions from those that belong to classes. Variables related to objects are called fields.

There are two types of fields in OOP. The first is the variables belonging to the whole class, the second is the variables of individual instances. Fields and methods together are class attributes. In Python, they are written in a block of code after the class keyword.

python class attributes

Methods and meaning of self

Methods are functions with the additional name self. It is added to the top of the parameter list. If desired, the variable can be called a different name, but such an initiative among programmers is not welcome. Self is a standard name that is easily recognizable in code. Moreover, some development environments are designed to work with it.

To better understand the meaning of self in OOP, imagine that we have a class named ClassA and methodA:

  • >>> class ClassA;
  • def methodA (self, argument1, argument2).

The objectA object is an instance of ClassA and the method call is as follows:

  • >>> objectA.methodA (argument1, argument2).

When the interpreter sees this line, it automatically converts it as follows: ClassA.methodA (objectA, argument1, argument2). That is, an instance of the class uses the self variable as a reference to itself.

python class inheritance

How to create class variables, methods, and instances

We offer to analyze a practical example from the interactive Python shell. Creating the Experiment First class begins with a compound class statement:

  • >>> class Experiment First:
  • def setinf (self, value): # create the first method with arguments
  • self.data = value
  • def display (self): # method two
  • print (self.data) # print instance data.

After the required indentation, a block with nested def statements follows, in which the setinf and display names are assigned to two function objects. With their help, the attributes ExperimentFirst.setinf and ExperimentFirst.display are created. In fact, any name that is assigned a value at the top level in a nested block becomes an attribute.

To see how the methods work, you need to create two instances:

  • >>> x = Experiment First () # Two instances are created;
  • >>> y = Experiment First () # Each is a separate namespace.

Initially, the copies do not store any information and are absolutely empty. But they are related to their class:

  • >>> x.setinf ("Learn Python") # Call a method in which self is x.
  • >>> y.setinf (3.14) # Equivalent: Experiment First.setinf (y, 3.14)

If you look at the .setinf attribute of the object of the Experiment First class through the name of the instances x, then as a result of a search in the inheritance tree, the interpreter returns the value of the class attribute.

  • >>> x.display () # x and y have their own values ​​self.data
  • Learn Python
  • >>> y.display ()
  • 3.14.

python classes examples

Operator Overload

In Python, classes can overload expression operators . This feature makes instances look like built-in data types. The process is to implement methods with special names starting and ending with double underscores.

Consider __init__ and __sub__ in action. The first method is called the class constructor. In Python, __init__ overloads the instantiation operation. The second __sub__ method implements the subtraction operation.

  • >>> class Overload: # a new class is created
  • def __init __ (self, start):
  • self.data = start
  • def __sub __ (self, other): # instance minus other
  • return Overload (self.data - other) # The result will be a new instance
  • >>> A = Overload (10) #__ init __ (A, 10)
  • >>> B = A - 2 #__ sub __ (B, 2)
  • >>> B.data #B is a new instance of the Overload class
  • 8.

More on the __init__ method

The __init__ method is used most often when working with classes. It is indispensable for initializing various objects. __init__ does not need to be called separately. When creating a new instance, the method automatically receives the arguments indicated in parentheses.

Using overload methods, you can implement any operations with built-in data types. Most are used only when solving special problems in which it is necessary for objects to imitate the behavior of standard objects.

Methods inherit from superclasses and are optional. In the initial stages, you can easily do without them. But for a complete immersion in programming and the essence of OOP, you need the skill of working with operators.

python class constructor

__Getitem__ method

The __getitem__ method overloads access to an element by index. If it is inherited or is present in the class definition, then at each indexing operation the interpreter will call it automatically. For example, when an instance of F appears in an element retrieval expression by index, such as F [i], the Python interpreter calls the __getitem__ method, passes the F object in the first argument, and the index specified in square brackets in the second.

The following Indexing Example class returns the square of the index value:

  • >>> class Indexing Example:
  • def __getitem __ (self, index):
  • return index ** 2
  • >>> F = Indexing Example ()
  • >>> F [2] # The expression F [i] calls F .__ getitem __ (i)
  • 4
  • >>> for i in range (5):
  • print (F [i], end = "") # Calls __getitem __ (F, i) in each iteration
  • 0 1 4 9 16

Using the same method, you can perform the operation of extracting the slice, which is often resorted to while working with sequences. When processing lists, the standard operation syntax is as follows:

  • >>> List = [13, 6, “and”, “s”, 74.9]
  • >>> List [2: 4]
  • [“And”, “c”]
  • >>> List [1:]
  • [6, “and”, “s”, 74.9]
  • >>> List [: - 1]
  • [13, 6, “and”, “c”]
  • >>> List [:: 2]
  • [13, “and”, 74.9]

A class that implements the __getitem__ method:

  • >>> class Indexer:
  • my_list = [13, 6, “and”, “s”, 74.9]
  • def __getitem __ (self, index): # Called when indexing or retrieving a slice
  • print ("getitem:", index)
  • return self.my_list [index] # Performs indexing or retrieving a slice
  • >>> X = Indexer ()
  • >>> X [0] # When indexing, __getitem__ gets an integer
  • getitem: 0
  • thirteen
  • >>> X [2: 4] # When retrieving a slice, __getitem__ gets the slice object
  • getitem: slice (2, 4, None)
  • [“And”, “c”]

python class creation

Attribute Access

To get an attribute reference, the special __getattr__ method is used. It is called with the attribute name as a string in cases of detecting an attempt to get a link to a nonexistent or undefined attribute. When the interpreter can find the object in the inheritance tree, __getattr __. Is not called.

The method is convenient for generalized processing of attribute requests:

  • >>> class Gone:
  • def __getattr __ (self, atname):
  • if atname == "age":
  • return 20
  • else:
  • raise AttributeError, atname
  • >>> D = Gone ()
  • >>> D.age
  • 20
  • >>> D.name
  • AttributeError: name

The Gone class and its instance D do not have their own attributes. Therefore, when accessing D.age, the __getattr__ method is automatically called. The instance itself is passed as self, and the name of the undefined "age" in the atname string. The class returns the result of accessing the name D.age, despite the fact that it does not have this attribute.

If the class does not provide for attribute handling, the __getattr__ method throws a built-in exception, and thereby passes information to the interpreter that the name is actually undefined. In this case, an attempt to access the name D.name leads to an error.

The __setattr__ statement overload method works similarly, intercepting each attempt to assign a value to an attribute. If this method is written in the class body, the expression “self.attribute = value” will be converted to a call to the self .__ setattr _ method (“attribute”, value).

We have described only a few of the existing overload methods. The entire list is in the standard language manual and includes many more names.

Additional features

OOP is sometimes used for complex and non-standard tasks. Thanks to the inheritance of classes in Python, the behavior of built-in data types and their capabilities can be expanded and adapted.

If you're not comfortable with the fact that indexing in sequences starts from scratch, you can fix this with the class statement. To do this, create a subclass of type list with new names of all types and implement the necessary changes. Also in OOP in Python, there are function decorators, static methods, and many other complex and special techniques.

Source: https://habr.com/ru/post/K3716/


All Articles