Keywords: Python 3 | relative imports | star imports
Abstract: This article explores key changes in import statements in Python 3, focusing on the shift from implicit to explicit relative imports and restrictions on star import usage. Through detailed code examples and directory structures, it explains the design rationale behind these changes, including avoiding naming conflicts and improving code readability and maintainability. The article also discusses differences between Python 2 and Python 3, providing practical migration advice.
Introduction
Python 3 introduced significant improvements to the module import mechanism, primarily in relative imports and star imports. According to PEP 0404, Python 3 no longer supports implicit relative imports within packages, allowing only absolute imports and explicit relative imports. Additionally, star imports (e.g., from x import *) are restricted to module-level code. These changes aim to address naming conflicts and readability issues present in Python 2. This article explains these concepts in detail, with practical examples illustrating their application and migration strategies.
Relative Imports: Concept and Evolution
A relative import refers to importing a module relative to the current script or package location. In Python 2, developers could use implicit relative imports, but this could lead to ambiguity. Consider the following directory structure:
mypkg
├── base.py
└── derived.pyIn derived.py, if importing the BaseThing class from base.py, Python 2 allowed:
from base import BaseThingHowever, this implicit approach had potential issues. If a third-party package named base was installed system-wide, the interpreter might incorrectly import that package instead of the local base.py module, causing naming conflicts and unpredictable behavior.
Python 3 resolves this by introducing explicit relative imports. In derived.py, the correct import becomes:
from .base import BaseThingThe dot (.) indicates importing the base module from the current module's directory, equivalent to the path ./base.py. Similarly, double dots (..) move up one directory level, e.g., from ..mod import something corresponds to ../mod.py. Triple dots (...) move up two levels. Note that these paths are relative to the current module file's location, not the current working directory.
Restrictions on Star Imports
Star imports allow importing all public names from a module at once, but their usage is more restricted in Python 3. In Python 2, star imports could be used inside functions, for example:
def sin_degrees(x):
from math import *
return sin(degrees(x))Although permitted in Python 2, this triggers a syntax warning: SyntaxWarning: import * only allowed at module level. Using star imports in local scopes can lead to namespace pollution and debugging difficulties.
Python 3 completely prohibits star imports in non-module-level code. Developers must adopt more explicit import methods. For instance, the above function can be rewritten as:
def sin_degrees(x):
from math import sin, degrees
return sin(degrees(x))Or by moving the import to the module level:
from math import *
def sin_degrees(x):
return sin(degrees(x))This restriction enhances code clarity and maintainability, preventing errors caused by implicit imports.
Design Rationale and Migration Recommendations
The changes to import statements in Python 3 reflect a design shift towards greater explicitness and safety. Explicit relative imports eliminate ambiguity in intra-package imports, ensuring accurate module paths. Restrictions on star imports encourage developers to specify required names explicitly, reducing the risk of naming conflicts.
For projects migrating from Python 2 to Python 3, the following steps are recommended:
- Review all relative import statements, converting implicit imports to explicit forms (e.g., change
from base import Xtofrom .base import X). - Audit star import usage to ensure they appear only at the module level, or replace them with specific name imports.
- Use tools like
2to3orfuturizeto assist migration, but manually verify critical changes.
These adjustments not only aid compatibility but also improve overall code quality.
Conclusion
The modifications to import statements in Python 3, including the explicitness of relative imports and scope restrictions on star imports, represent significant steps in the language's evolution. By enhancing code clarity and safety, these changes support the development of larger and more complex projects. Developers should deeply understand these mechanisms and adhere to best practices in coding to fully leverage the advantages of Python 3.