Examples of working with classes in Python

by Alex
Examples of working with classes in Python

Python has been an object-oriented language since its inception. Therefore, creating and using classes and objects in Python is simple and easy. This article will help you understand Python’s object-oriented programming support with examples. If you have no experience with object-oriented programming (OOP), check out an introductory course or tutorial to understand the basic concepts.

Creating classes

The class operator creates a new definition of a class. The class name immediately follows the class keyword, followed by a colon:

class ClassName:
  """Optional class documentation string" ""  
   class_suite
  • The class has a documentation string that can be accessed via ClassName.__doc__.
  • the class_suite consists of class parts, data attributes, and a function.

An example of creating a class in Python:

 employeeclass 
   """Base class for all employees"" "  
    emp_count = 0 
  
   def __init__(self, name, salary) 
        self.name = name  
        self.salary = salary  
        Employee.emp_count += 1 
  
   def display_count(self) 
       print('Total employees: %d' % Employee.empCount) 
  
   def display_employee(self) 
       print('Name: {}. Salary: {}'.format(self.name, self.salary))
  • The variable emp_count is a class variable whose value is shared between instances of this class. You can access this variable through Employee.emp_count from the class or outside the class.
  • The first method __init__() is a special method called the class constructor or initialization method. It is called by Python when creating a new instance of that class.
  • Declare the other methods of the class as normal functions, except that the first argument for each method is self. Python adds the self argument to the list for you; and then you don’t need to include it when you call these methods.

Creating instances of a class

To create instances of classes, you need to call the class using its name and pass the arguments that the __init__ method takes.

# This will create the first object of the Employee class  
 emp1 = Employee("Andrew", 2000) 
# This will create the second object of the Employee class  
 emp2 = Employee("Maria", 5000) 

Accessing Attributes

Access class attributes using the . operator after the class object. You can access a class using the name of the class variable:

emp1.display_employee() 
emp2.display_employee() 
print("Total employees: %d" % Employee.emp_count)

Now, systematize everything.

 employeeclass 
   """Base class for all employees"" "  
    emp_count = 0 
  
   def __init__(self, name, salary) 
        self.name = name  
        self.salary = salary  
        Employee.emp_count += 1 
  
   def display_count(self) 
       print('Total employees: %d' % Employee.emp_count)
        
   def display_employee(self) 
       print('Name: {}. Salary: {}'.format(self.name, self.salary)) 
  
  
# This will create the first object of the Employee class  
 emp1 = Employee("Andrew", 2000) 
# This will create the second object of class Employee  
 emp2 = Employee("Maria", 5000) 
emp1.display_employee() 
emp2.display_employee() 
print("Total employees: %d" % Employee.emp_count)

When we execute this code, we get the following result:

Name: Andrei. Salary: 2000
Name: Maria. Salary: 5000
Total employees: 2

You can add, remove, or change class and object attributes at any time.

emp1.age = 7 # Adds the 'age' attribute
emp1.age = 8 # Change the 'age'attribute
del emp1.age # Deletes the 'age'attribute

Instead of using the usual operators to access attributes, you can use these functions:

  • getattr(obj, name [, default]) – to access an object attribute.
  • hasattr(obj, name) – check if obj has the name attribute.
  • setattr(obj, name, value) – set the attribute. If the attribute does not exist, it will be created.
  • delattr(obj, name) – remove the attribute.
hasattr(emp1, 'age') # returns true if the 'age' attribute exists
getattr(emp1, 'age') # returns the value of the 'age' att ribute 
setattr(emp1, 'age', 8) # sets the 'age' attribute to 8
delattr(empl, 'age') # removes the 'age'attribute

Embedded class attributes

Every Python class stores built-in attributes, and provides access to them through the operator . operator, just like any other attribute:

  • __dict__ is the dictionary containing the class namespace.
  • __doc__ is the documentation string of the class. None if there is no documentation.
  • __name__ – class name.
  • __module__ – name of the module where the class is defined. This attribute is __main__ in interactive mode.
  • __bases__ – can be empty tuple, containing base classes, in the order they appear in the base class list.

For the class above, let’s try to access all of these attributes:

 employeeclass 
   """Base class for all employees"" "  
    emp_count = 0 
  
   def __init__(self, name, salary) 
        self.name = name  
        self.salary = salary  
        Employee.empCount += 1 
  
   def display_count(self) 
       print('Total employees: %d' % Employee.empCount) 
  
   def display_employee(self) 
       print('Name: {}. Salary: {}'.format(self.name, self.salary)) 
  
print('Employee.__doc__:', Employee.__doc__) 
print('Employee.__name__:", Employee.__name__) 
print("Employee.__module__:", Employee.__module__) 
print("Employee.__bases__:", Employee.__bases__) 
print("Employee.__dict__:", Employee.__dict__) 

When this code is executed, it returns this result:

Employee.__doc__: Base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: (<class 'object'>,)
Employee.__dict__: {'__module__': '__main__', '__doc__': 'Base class for all employees', 'emp_count': 0, '__init__': <function Employee.__init__ at 0x03C7D7C8>, 'display_count': <function Employee.display_count at 0x03FA6AE0>, 'display_employee': <function Employee.display_employee at 0x03FA6B28>, '__dict__': <attribute '__dict__' of 'Employee' objects>, '__weakref__': <attribute '__weakref__' of 'Employee' objects>}

Deleting objects (garbage collection)

Python automatically removes unnecessary objects (built-in types or class instances) to free up memory space. Using the ‘Garbage Collection’ process, Python periodically recovers blocks of memory that are no longer in use. The Python garbage collector runs at runtime and when the number of references to an object reaches zero. As the number of calls to it changes, the number of references changes. When an object is assigned to a new variable or added to a container (list, tuple, dictionary), the number of object references increases. The number of references to an object decreases when it is deleted with del, or its reference goes out of scope. When the number of references reaches zero, Python automatically collects it.

a = 40 # created an <40> object
b = a # increases the number of references <40&gt 
c = [b] # increment the number of links <40&gt 

del a # decreases the number of links <40>
b = 100 # decreases the number of links <40&gt 
c[0] =-1 # decreases the number of links <40>

Normally you won’t notice when the garbage collector destroys an instance and clears its space. But the class can implement a special __del__() method called the destructor. It is called before destroying the instance. This method can be used to clean up any memory resources. An example of how __del__() works The __del__() destructor tells you the class name of the instance to be destroyed:

class Point 
   def __init__(self, x=0, y=0) 
        self.x = x 
        self.y = y 
  
   def __del__(self) 
        class_name = self.__class__.__name__  
       print('{} destroyed'.format(class_name)) 
  
  
pt1 = Point() 
pt2 = pt1  
pt3 = pt1  
print(id(pt1), id(pt2), id(pt3)) # print id of the objects  
 del pt1  
del pt2  
del pt3

When the above code is executed and outputs the following:

17692784 17692784 17692784
Point destroyed

Ideally, you should create your classes in a separate module. Then import them into the main program module with import SomeClass

.

Class inheritance in python

Inheritance is the process whereby one class inherits the attributes and methods of another. The class whose properties and methods are inherited is called a Parent or Superclass. And the class whose properties are inherited is the child class or Subclass.

Instead of starting from scratch, you can create a class based on an existing one. Specify the parent class in parentheses after the name of the new class. The descendant class inherits the attributes of its parent class. You can use these attributes as if they were defined in the descendant class. It can override the parent’s data elements and methods.

Class Inheritance Syntax

Inheritor classes are declared in the same way as parent classes. Only, the list of inherited classes, is specified after the class name.

class SubClassName(ParentClass1[, ParentClass2, ...]):
	"""Optional class documentation string" "" 
	class_suite

Example of class inheritance in Python

class Parent: # declare parent class  
    parent_attr = 100 
  
   def __init__(self) 
       print('Parent constructor call') 
  
   def parent_method(self) 
       print('Parent method call') 
  
   def set_attr(self, attr) 
        Parent.parent_attr = attr  
  
   def get_attr(self) 
       print('Parent attribute:{}'.format(Parent.parent_attr)) 
  
  
class Child(Parent): # declare heir class  
   def __init__(self) 
       print('Calling the constructor of the heir class') 
  
   def child_method(self) 
       print('Call the method of the heir class') 
  
  
c = Child() # an instance of the Child class  
c.child_method() # call child_method  
c.parent_method() # call  parent_method  
c.set_attr(200) # call parent_method again  
c.get_attr() # call the parent method again

When this code runs, it outputs the following result:

Calling a constructor of an inherited class
Calling a method of an inherited class
Call of a parent method
Parent attribute: 200

Similarly, you can control a class with multiple parent classes:

class A: # declare class A
...

class B: # declare class B
...

class C(A, B): # C inherits from A and B
...

You can use issubclass() or isinstance() to check the relationship of two classes and instances.

  • The logic function issubclass(sub, sup) returns True if the given subclass sub is indeed a subclass of sup.
  • The logical function isinstance(obj, Class) returns True if obj is an instance of Class or is an instance of a subclass of Class.

Overriding methods

You can always override methods of the parent class. You may need special functions in your subclass. This is one reason for overriding parent methods. An example of overriding methods:

class Parent: # declare parent class  
   def my_method(self) 
       print('Parent method call') 
  
  
class Child(Parent): # declare heir class  
   def my_method(self) 
       print('Heir method call') 

  
c = Child() # an instance of the Child class  
c.my_method() # method overridden by heir class

When this code is executed, it produces the following result:

Calling an inherited method

Popular Basic Methods

This table lists some common functions. You can override them in your own classes.

Method, description and example call
1 __init__(self [, args...]) – constructor (with any optional arguments) obj = className(args)
2 __del__(self) – the destructor, deletes the object del obj
3 __repr__(self) – program representation of the object repr(obj)
4 __str__(self) – string representation of the object str(obj)

An example of using __add__

Suppose you created a Vector class to represent two-dimensional vectors. What happens when you use an additional operator to add them? Python will probably be against it. However, you can define a __add__ method in your class to add vectors and the + operator will behave as it should.

 vectorclass  
   def __init__(self, a, b) 
        self.a = a 
        self.b = b 
    
   def __str__(self)   
       return 'Vector ({}, {})'.format(self.a, self.b) 
    
   def __add__(self, other)  
       return Vector(self.a + other.a, self.b + other.b) 
     
     
v1 = Vector(2, 10)  
v2 = Vector(5,-2)  
print(v1 + v2)

When you execute this code, we get:

Vector(7, 8)

Private methods and attributes

Class attributes may not be visible outside of the class definition. You need to specify attributes with __ first, and those attributes will not be called outside the class. An example of a private attribute:

class JustCounter 
    __secret_count = 0 
  
   def count(self) 
        self.__secret_count += 1 
       print(self.__secret_count) 
  
  
counter = JustCounter() 
counter.count() 
counter.count() 
print(counter.__secret_count)

When you execute this code, we have the following result:

1
2
Traceback (most recent call last):
   File "test.py", line 12, in <module>
     print(counter.__secret_count)
AttributeError: 'JustCounter' object has no attribute '__secret_count'

You can access such attributes as object._className__attrName. If you replace your last line with the following, it will work.

...
print(counter._JustCounter__secret_count)

When you execute the code, you get the result:

1
2
2

Related Posts

LEAVE A COMMENT