Intermediate- Python Developer Interview - part 4

Intermediate- Python Developer Interview - part 4

Modules, logging, Error handling

Hey all, in this article we are going to discuss the following intermediate-level Python topics: Modules, packages, logging, Error handling . So let's see them one by one.

Modules and Packages:

What are modules?

Modules are nothing but files with .py extensions which consist of Python code. You can use this code directly by importing these modules in another file. This is the simplest definition of a module. Whenever you import the file at that time _name_ variable has a value equal to the file name and when you run the module as :

python test_module.py <arguments>

_name_ is set to "_main_"

How we can use modules?

Modules can be used by using the "import" statement as mentioned below:

import test_module

Modules also can import other modules. If you want to run a module as a script then _name_ should be set to "_main_"

The module search path:

The module is searched at three locations in the below order:

  1. The directory containing the input script (or the current directory when no file is specified).

  2. PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).

  3. The installation-dependent default (by convention including a site-packages directory, handled by the site module).

What is the difference between .py and .pyc files?

  • To speed up loading modules, Python caches the compiled version of each module in the pycache directory under the name module.version.pyc, where the version encodes the format of the compiled file; it generally contains the Python version number.

  • .py files contain the source code of a program. Whereas, .pyc file contains the bytecode of your program. We get bytecode after compilation of .py file (source code). .pyc files are not created for all the files that you run. It is only created for the files that you import.

What are packages?

  • Packages are nothing but a collection of modules. This is the simplest definition of a package. As per official documentation of Python "Packages are a way of structuring Python’s module namespace by using “dotted module names”. For example, the module name A.B designates a submodule named B in a package named A."

Note: _init_ file inside the package is important because it lets Python know that the directory containing the _init_ file is the package.

How to import all the modules inside the package?

There are two ways to achieve this:

  1. By importing all the modules in __init__.py file in the package directory, you need to specify import pkg.mod1, pkg.mod2 in __init__.py file. You can then access the imported modules using the package name as a prefix, for ex. "mypackage.module1" , "mypackage.module2"

  2. Using __all__ in __init__.py file in the package directory. __all__ will contain the list of the modules that the package author wants to be accessible. So whenever you try to use from <package_name> import * it will bring all the modules which are mentioned in the list of __all__ . If you don't have any list then from <package_name> import * statement will not work.

    Here's an example of __init__.py file:

     # __init__.py
    
     __all__ = [
         'order',
         'delivery'
     ]
    

Logging in Python:

While working on any project we encounter several issues, if the project is smaller then we can easily debug the issues, but as the size of the project increases debugging gets difficult. Logging will help us in identifying the issues efficiently. It does not only help in debugging but can also help track the performance of your application, you can log the relevant information in your application so that it will help in further analysis. Python has a built-in module named "logging". This module allows us to log different levels of log messages.

What are different log levels and when do we need to use them?

According to the official documentation following are the five logging levels of logging present in Python:

  • DEBUG: Detailed information, typically of interest only when diagnosing problems.

  • INFO: Confirmation that things are working as expected.

  • WARNING: An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected.

  • ERROR: Due to a more serious problem, the software has not been able to perform some functions.

  • CRITICAL: A serious error, indicating that the program itself may be unable to continue running.

The default level is WARNING, which means that only events of this level and above will be tracked unless the logging package is configured to do otherwise.

Error handling in Python:

While working on any project it is really common to face several errors. We must be able to identify the error and act accordingly. Sometimes we don't want to stop the execution of the program if a particular error occurs, here error handling comes to the rescue.

Exception handling makes debugging easier and the code is cleaner. There are (at least) two distinguishable kinds of errors: syntax errors and exceptions.

  1. Syntax error:

    Syntax errors, also known as parsing errors, are perhaps the most common kind of complaint you get while you are still learning Python:
    while True print('Hello world') File "<stdin>", line 1 while True print('Hello world') ^ SyntaxError: invalid syntax

  2. Exceptions:

    Even if a statement or expression is syntactically correct, it may cause an error when an attempt is made to execute it. Errors detected during execution are called exceptions and are not unconditionally fatal.
    10 (1/0) Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero >>> 4 + spam3 Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'spam' is not defined >>> '2' + 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can only concatenate str (not "int") to str

Now let's see how the exception handling is done:

Try and except statements are used to catch and handle exceptions in Python. The code which may raise an exception is kept inside the try block and in except block we will have the code which will be executed if the exception is raised. Following is the example of the try except block:

x = 5
y = "hello"
try:
    z = x + y
except:
    print("error occurred")

#output
error occurred

If you don't use the try and except block then the error will be generated as below:

x = 5
y = "hello"
z = x + y

#output:
Traceback (most recent call last):
  File "<string>", line 5, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Try can have multiple except statements as shown in below :

try:
   ...
except FirstException:
   handle_first_one()

except SecondException:
   handle_second_one()

except (ThirdException, FourthException, FifthException) as e:
   handle_either_of_3rd_4th_or_5th()

except Exception:
   handle_all_other_exceptions()

Try-except statement can be used with else statement as well. Else is executed if exception is not raised withing try block. Below is the example of same:

x = 5
y = 7
try:
    z = x + y
except:
    print("error occurred")
else:
    print("no error")

Now let's see try-except statement with finally block. Finally is executed regardless of exception is raised or not.

# Python program to demonstrate finally

x = 5
y = "hi"
try:
    z = x + y
except Exception as e:
    print(f"error occurred {e}")
finally:
    print("finally is executed")

#output:
error occurred unsupported operand type(s) for +: 'int' and 'str'
finally is executed

As you see in the above example we have used except Exception as e, it will catch all the exceptions. Ideally, we should not do this, there are several types of exceptions, if we directly use except Exception as e then we won't be able to catch specific type of exception.

What we learned in this article:

  • What is a module in Python and how to access them

  • What is a package and how to import modules from packages

  • How does logging work in Python and what are the different levels of logging

  • What is error handling and how we can use different conditions in it.

References