杰瑞科技汇

Python import_是做什么用的?

Of course! Let's dive deep into Python's __import__() function.

Python import_是做什么用的?-图1
(图片来源网络,侵删)

What is __import__()?

In Python, __import__() is a built-in function that is the underlying mechanism for the import statement. While you should almost always use the standard import statement in your code, understanding __import__() is valuable for understanding how imports work under the hood and for advanced dynamic use cases.

The __import__() function executes the import statement and returns the top-level module of the package you are importing.


The Standard import Statement vs. __import__()

First, let's look at the standard way we import modules.

# Standard import statement
import collections

This is clean, readable, and the recommended way. It makes the collections module available in your current namespace.

Python import_是做什么用的?-图2
(图片来源网络,侵删)

Now, let's achieve the exact same thing using __import__().

# Using __import__() to get the 'collections' module
collections_module = __import__('collections')
# Let's check what we got
print(collections_module)
# Output: <module 'collections' from ...>
# We can use it just like the standard import
print(collections_module.Counter)
# Output: <class 'collections.Counter'>

In this simple case, __import__('collections') returned the collections module itself.


The Crucial Difference: Importing Submodules

This is where __import__() behaves differently from what you might expect. Let's try to import collections.abc.

# Our goal: get the 'collections.abc' module
# This is what we would LIKE to happen:
# import collections.abc
# print(collections.abc) # This would work
# What actually happens with __import__():
abc_module = __import__('collections.abc')
print(abc_module)
# Output: <module 'collections' from ...>

Surprise! __import__('collections.abc') did not return the collections.abc module. It returned the top-level module, which is collections.

Python import_是做什么用的?-图3
(图片来源网络,侵删)

Why? The __import__() function's primary job is to execute the import statement. When Python sees import collections.abc, it needs to ensure the collections package is loaded first. The function returns the first module it successfully imports, which is the top-level one.


How to Actually Get the Submodule with __import__()

If you want __import__() to return the last (or specific) module in the dotted path, you need to use its second argument, fromlist.

The signature is: __import__(name, globals=None, locals=None, fromlist=(), level=0)

  • name: The module name (e.g., 'collections.abc').
  • fromlist: A list of names to be imported from the module. This is the key. If fromlist is non-empty, __import__() will return the last module in the name path instead of the top-level one.

Let's try again:

# Use fromlist to get the submodule
abc_module = __import__('collections.abc', fromlist=[''])
print(abc_module)
# Output: <module 'collections.abc' from ...>
# Now it works as expected!
print(abc_module.Mapping)
# Output: <class 'collections.abc.Mapping'>

How does fromlist work?

  • If fromlist is empty (or not provided), __import__ returns the top-level package.
  • If fromlist is not empty, __import__ traverses the entire dotted path and returns the final module object.

A common trick is to pass fromlist=['*'] or fromlist=[''] (an empty string is sufficient) to signal that you want the final module.


Practical Use Case: Dynamic Imports

The main reason to use __import__() is when you don't know the name of the module you want to import until your program is running. This is called dynamic importing.

Scenario: You have a configuration file or user input that specifies a module to load.

Example:

Let's say we have two files: my_math_module.py

def add(a, b):
    return a + b

my_string_module.py

def reverse(s):
    return s[::-1]

Now, let's create a main program that dynamically imports one of these modules based on user input.

dynamic_importer.py

import importlib # A more modern and recommended way for dynamic imports
# Let's first show the __import__ way
def load_module_with_import(module_name):
    """Loads a module using __import__()."""
    print(f"\n--- Attempting to load '{module_name}' with __import__() ---")
    try:
        # We use fromlist to get the actual module, not the top-level package
        module = __import__(module_name, fromlist=['*'])
        print(f"Successfully loaded: {module}")
        return module
    except ImportError:
        print(f"Error: Could not find or import the module '{module_name}'.")
        return None
# --- Main Program ---
if __name__ == "__main__":
    module_to_load = input("Which module to load? (my_math_module or my_string_module): ")
    math_module = load_module_with_import("my_math_module")
    if math_module:
        print(f"Result from math module: {math_module.add(5, 3)}")
    string_module = load_module_with_import("my_string_module")
    if string_module:
        print(f"Result from string module: {string_module.reverse('hello')}")

When you run dynamic_importer.py and type my_math_module, it will correctly load and use it.


The Modern Alternative: importlib

While __import__() works, the Python documentation strongly recommends using the importlib module for any programmatic importing. It's more powerful, explicit, and easier to understand.

The importlib.import_module() function is the direct, modern replacement for dynamic imports.

Let's rewrite our dynamic importer using importlib:

import importlib
def load_module_with_importlib(module_name):
    """Loads a module using the modern importlib."""
    print(f"\n--- Attempting to load '{module_name}' with importlib ---")
    try:
        # import_module() does exactly what we want: returns the specified module
        module = importlib.import_module(module_name)
        print(f"Successfully loaded: {module}")
        return module
    except ImportError:
        print(f"Error: Could not find or import the module '{module_name}'.")
        return None
# --- Main Program ---
if __name__ == "__main__":
    module_to_load = input("Which module to load? (my_math_module or my_string_module): ")
    math_module = load_module_with_importlib("my_math_module")
    if math_module:
        print(f"Result from math module: {math_module.add(5, 3)}")
    string_module = load_module_with_importlib("my_string_module")
    if string_module:
        print(f"Result from string module: {string_module.reverse('hello')}")

Why is importlib better?

  • Clarity: importlib.import_module('collections.abc') clearly and unambiguously returns the collections.abc module. You don't have to remember the fromlist trick.
  • Intention: Using importlib signals to other developers that you are intentionally performing a dynamic import.
  • Features: importlib provides a richer API for importing, including importing files by path (importlib.util.spec_from_file_location) and reloading modules (importlib.reload).

Summary: When to Use What

Method When to Use Pros Cons
import my_module Almost always. This is the standard, readable way to import modules. Highly readable, clear intent, checked by static analysis tools. Not dynamic. Module name must be known at compile time.
__import__() Rarely. Only for very specific, low-level dynamic imports or when you need to replicate the exact behavior of the import statement for introspection. Built-in, part of the language core. Confusing behavior (returns top-level module by default), less readable than import, importlib is preferred.
importlib.import_module() For dynamic imports. When the module name is determined at runtime. Clear, explicit, modern, and robust. The standard, recommended way for programmatic importing. Requires an import (import importlib).

Final Recommendation:

  • For 99% of your code, use the standard import statement.
  • If you need to import a module dynamically, use importlib.import_module().
  • Avoid using __import__() directly unless you have a very specific reason and understand its nuances.
分享:
扫描分享到社交APP
上一篇
下一篇