Python tutorials > Modules and Packages > Packages > How to import from packages?

How to import from packages?

Packages in Python are a way of structuring Python’s module namespace by using 'dotted module names'. A package is essentially a directory with Python module file(s) and a file named __init__.py, which can be empty. This tutorial covers various ways to import modules from packages.

Basic Package Structure

Before diving into the import statements, let's define a basic package structure: my_package/ __init__.py module_a.py module_b.py subpackage/ __init__.py module_c.py Here, `my_package` is the main package. `module_a.py` and `module_b.py` are modules directly inside the package. `subpackage` is a subpackage, and `module_c.py` is a module within the subpackage. Each directory containing Python code also needs a `__init__.py` file (which can be empty, especially in Python 3.3+ where implicit namespace packages were introduced), signifying that the directory should be treated as a Python package. The `__init__.py` file is executed when the package or a module in the package is first imported.

Importing Entire Packages

This imports the entire `my_package` package. However, it only makes the package name available; it doesn't directly import the modules inside. To access modules and functions within the package, you need to use the dotted notation. Note that unless specified inside my_package/__init__.py nothing from the modules module_a and module_b is automatically imported.

import my_package

# Accessing members requires specifying the package name
my_package.module_a.some_function()

Importing Specific Modules

This imports a specific module (`module_a`) from the `my_package`. You can then access the functions and classes within `module_a` using the module name. The from my_package import module_b form directly imports the module_b into the current namespace, allowing direct access without prefixing with my_package.

import my_package.module_a

# Accessing members through the imported module name
my_package.module_a.some_function()

from my_package import module_b

# Accessing members directly
module_b.another_function()

Importing Specific Members from Modules

This imports specific functions or classes directly from a module into your current namespace. This avoids the need to repeatedly prefix with the module name. You can also use the `as` keyword to create an alias for the imported member.

from my_package.module_a import some_function

# Accessing the function directly
some_function()

from my_package.module_b import another_function as alias_function

# Accessing the function through its alias
alias_function()

Importing from Subpackages

The same principles apply to importing from subpackages. You can import the subpackage and modules contained within, similarly to how you import from the top-level package.

import my_package.subpackage.module_c

# Accessing members requires specifying the full path
my_package.subpackage.module_c.yet_another_function()

from my_package.subpackage import module_c

# Accessing members directly through the imported module name
module_c.yet_another_function()

The __init__.py File

The `__init__.py` file can be used to initialize the package, set up package-level variables, and import modules to make them directly accessible from the package. Using a relative import like from . import module_a makes module_a available directly from the package namespace (e.g., `my_package.module_a`). The `__all__` variable defines a list of module names that should be imported when using `from package import *`. This is good practice to control what gets imported and prevent namespace pollution.

python
# my_package/__init__.py
from . import module_a
from .module_b import another_function

__all__ = ['module_a', 'module_b']

python
# main script
import my_package

my_package.module_a.some_function()
my_package.another_function()

Concepts Behind the Snippet

Python packages help organize related modules into a hierarchical namespace. This avoids naming collisions, improves code maintainability, and promotes reusability. The __init__.py file acts as the package's constructor, potentially performing initialization actions and defining the package's namespace.

Real-Life Use Case Section

Consider a web framework organized as a package. It might contain subpackages for routing, database management, templating, and authentication. For example, a directory structure might look like `web_framework/`, with subdirectories `routing/`, `database/`, etc., each containing modules implementing the framework's features. A game development library could be structured similarly, separating concerns like graphics, audio, and input handling into distinct subpackages.

Best Practices

  • Explicitly import what you need to enhance readability and avoid namespace pollution.
  • Use the `as` keyword for aliasing when necessary to avoid naming conflicts or to shorten long module names.
  • Structure your packages logically to reflect the organization of your code.
  • Use relative imports (`from . import module`) within packages for better maintainability.
  • Keep your `__init__.py` files concise and focused on essential package initialization.

Interview Tip

Be prepared to explain the role of the `__init__.py` file and the differences between different import statements (e.g., `import package`, `from package import module`, `from package.module import member`). Understand how to use `__all__` to control what gets imported when using `from package import *`.

When to Use Them

Use packages when your project contains a significant number of modules that are logically related. Packages help to reduce complexity, improve code organization, and promote reusability. If your project consists of only a few modules, packages might be overkill, but for larger projects, they are essential.

Memory Footprint

Importing an entire package (e.g., `import my_package`) initially has a relatively small memory footprint because it only loads the package's namespace. However, importing specific modules or members (`from my_package import module_a` or `from my_package.module_a import function`) will load those modules or members into memory, increasing the memory footprint. Be mindful of what you import, especially in memory-constrained environments. Avoid wildcard imports (`from package import *`) as they can lead to importing unnecessary modules and increasing memory usage.

Alternatives

Alternatives to using packages directly include using namespace packages (PEP 420) which don't require __init__.py files, or employing design patterns that minimize inter-module dependencies and reduce the need for extensive package structuring. In very small projects, simply organizing modules within a single directory might suffice.

Pros

  • Improved Code Organization: Packages help organize related modules, making your code more structured and easier to understand.
  • Namespace Management: Packages prevent naming collisions by creating separate namespaces for each package and its modules.
  • Reusability: Packages promote code reusability by allowing you to group related functionality into a single, distributable unit.
  • Modularity: Packages enhance modularity by allowing you to break down large projects into smaller, more manageable components.

Cons

  • Increased Complexity: Packages add a layer of complexity to your project, especially for beginners.
  • Import Overhead: Importing modules from packages can sometimes be more verbose than importing from a single directory.
  • Potential for Circular Dependencies: Improper package design can lead to circular dependencies, making the code harder to maintain.

FAQ

  • What is the purpose of the __init__.py file?

    The __init__.py file is used to mark a directory as a Python package. It is executed when the package or a module in the package is first imported. It can be used to initialize the package, set up package-level variables, and import modules to make them directly accessible from the package.
  • What is the difference between import package and from package import module?

    import package imports the entire package but does not directly import any of the modules within it. You need to use the dotted notation to access the modules (e.g., package.module.function()). from package import module imports a specific module from the package directly into the current namespace, allowing you to access its members directly (e.g., module.function()).
  • How can I control which modules are imported when using from package import *?

    You can define the __all__ variable in the package's __init__.py file. This variable should be a list of module names that should be imported when using from package import *. This is good practice to control what gets imported and prevent namespace pollution.