Modules & Packages

Modules & Packages

Modules in Python allow us to organize our code and reuse code across programs. Some key points about modules in Python:

  • A module is a .py file that contains functions, classes or variables that we want to import and use in our main program.

  • We can import a module using the import statement. For example:

import math

This imports the entire math module.

  • We can import specific functions from a module using:
from math import sqrt, log

This imports only the sqrt and log functions from the math module.

  • After importing, we can use the functions defined in the module. For example:
import math
result = math.sqrt(25)
  • We can give an alias name to a module using the as keyword:
import math as m
result = m.sqrt(16)
  • Modules help avoid namespace collisions. The functions/variables in one module won't affect other modules.

  • The main advantage of modules is that it allows us to organize our code into logical chunks and reuse code across programs.

So in summary, modules allow us to logically organize our Python code into reusable components and avoid namespace collisions.


Packages in Python are namespaces that contain multiple modules. They provide a way to structure Python's module namespace by using "dotted module names". Some key points about packages in Python:

  • A package is a directory containing one or more Python module files.

  • The init.py file is required to make Python treat the directory as containing a package.

  • We can import modules from a package using dotted module names, like this:

import package_name.module_name
from package_name import module_name
  • We can also import all modules from a package using:
from package_name import *
  • Package paths must be absolute or relative to the current module. For example:
import sys
sys.path.append("/some/package/path")
  • Packages allow us to organize related modules into namespaces and avoid module name conflicts.

  • Packages can also contain subpackages. We can have hierarchical package structures.

  • The main advantages of packages are:

    • Organize Python code into logical groupings.

    • Avoid name conflicts.

    • Make code reuse possible.

In summary, packages provide a mechanism for structuring Python modules so that related modules can be maintained together and used more easily. They form a namespace containing multiple modules.


init.py files are used to make Python treat directories containing the file as packages.

The init.py file can contain:

  • Import statements to import module within the package. This makes the imports shorter. For example, instead of importing:
import package_name.module_name

You can import in init.py as:

from .module_name import *

Then you can simply import:

import package_name
  • Class and function definitions that you want to make available when the package is imported.

  • Package level variables that you want to make available.

  • The all variable which controls what names are visible when using from package import *.

So in summary, init.py files:

  • Make Python treat the directories containing them as packages.

  • Can contain import statements to import modules within the package.

  • Can define classes, functions and variables to expose at package level.

  • Can define the __all__ variable to control what names are visible during from package import * imports.

Without an init.py file, Python will treat the directory as a normal package, and modules within the package may not be importable.


Here is an example of what an init.py file may contain:

# __init__.py

# Package level variable 
version = '1.0'

# Function definition
def print_hello():
    print("Hello from the package!")

# Class definition     
class PackageClass:
    pass

# __all__ variable to control imports    
__all__ = ['version', 'print_hello', 'PackageClass']

This init.py:

  • Defines a package level variable version

  • Defines a function print_hello()

  • Defines a class PackageClass

  • Defines the Here is an example of what an init.py file may contain:

      # __init__.py
    
      # Package level variable 
      version = '1.0'
    
      # Function definition
      def print_hello():
          print("Hello from the package!")
    
      # Class definition     
      class PackageClass:
          pass
    
      # __all__ variable to control imports    
      __all__ = ['version', 'print_hello', 'PackageClass']
    

    This init.py:

    • Defines a package level variable version

    • Defines a function print_hello()

    • Defines a class PackageClass

    • Defines the __all__ variable to contain the names that will be imported when using from package import *

So if this init.py is in a package called mypackage, we can import it as:

    import mypackage

    print(mypackage.version)
    mypackage.print_hello()
    myclass = mypackage.PackageClass()

Or using:

    from mypackage import *

    print(version)
    print_hello()
    myclass = PackageClass()

Hope this example helps illustrate the possible contents of an init.py file! Let me know if you have any other questions. variable to contain the names that will be imported when using from package import *

So if this init.py is in a package called mypackage, we can import it as:

import mypackage

print(mypackage.version)
mypackage.print_hello()
myclass = mypackage.PackageClass()

Or using:

from mypackage import *

print(version)
print_hello()
myclass = PackageClass()

Hope this example helps illustrate the possible contents of an init.py file! Let me know if you have any other questions.


The __all__ variable has two underscores before and after its name for a few reasons:

  1. It follows Python's convention for "magic" or internal variables. Variables with a double leading and trailing underscore are meant to be used internally by Python.

  2. It avoids name clashes with user-defined variables. Since __all__ is an internal Python variable, the chances of a user defining their own variable with the same name is less.

  3. It makes the variable stand out as special. The double underscores make it clear that __all__ is a special variable used by Python, not an ordinary variable defined by the user.

  4. It helps avoid potential conflicts if a user defines a variable named all (without the double underscores). Since __all__ has the double underscores, it won't conflict with a normal all variable.

So in summary, the double underscores around __all__ follow Python's convention for "magic" or internal variables. This helps avoid name clashes, makes the variable stand out as special, and avoids potential conflicts with user-defined variables.

Hope this explanation of why __all__ has double underscores makes sense! Let me know if you have any other questions.


Disclaim: This article is created by Rix usinq Quick mode. I have ask the questions required to understand about packages and modules. If you do not understand this topic feel free to ask more questions.