Python内部如何区分from包导入模块与from模块导入函数?
from...import... for Packages vs Modules Nice question! Let’s break down exactly how Python’s interpreter processes from A import B, and whether it distinguishes between packages and modules upfront.
The Short Answer
Python doesn’t first "check if A is a package or module" as a separate step. Instead, it treats both packages and modules as the same core type of object (a module object)—with just a few extra behaviors for packages. The import process follows a unified flow, with differences emerging only when handling what happens after A is loaded.
Step 1: Loading "A" (Package or Module)
When the interpreter sees from A import B, its first task is to locate and load A using the sys.path search order:
- If it finds a file named
A.py, that’s a regular module. The interpreter loads this file, executes its code, and creates amoduleobject to represent it. - If it finds a folder named
A(either with an__init__.pyfile, or a namespace package in Python 3.3+), that’s a package. The interpreter loads the__init__.pyfile (if it exists) to create amoduleobject—this object just has an extra__path__attribute that points to the package’s directory (or directories, for namespace packages).
Key point: Run type(A) after importing, and you’ll see <class 'module'> for both packages and regular modules. Packages are just specialized modules.
Step 2: Finding "B" in A’s Namespace
Once A is loaded (as a module object), the interpreter looks for B directly in A’s namespace (stored in A.__dict__):
- If A is a regular module:
Bcan be any function, class, variable, or imported object defined inA.py. For example:from math import sqrt # sqrt is a function in the math module's namespace - If A is a package:
Bcan be two things:- An object defined directly in
A/__init__.py(like a function or variable). - A sub-module or sub-package inside the
Afolder. In this case, the interpreter uses A’s__path__attribute to locate the sub-module (e.g.,A/B.pyorA/B/__init__.py), loads it, and adds it to A’s namespace. For example:from my_package import utils # utils is a sub-module loaded from my_package/utils.py
from my_package import my_func), you need to explicitly importmy_funcintomy_package/__init__.pyfirst—otherwise, the interpreter won’t find it in the package’s top-level namespace. - An object defined directly in
Extra: What Makes Packages Special?
The only real difference between a package and a regular module is the __path__ attribute:
- Regular modules don’t have
__path__. - Packages use
__path__to tell the interpreter where to look for sub-modules and sub-packages. - Namespace packages (no
__init__.py) have a__path__that includes multiple directories, letting you split a package across different locations on your filesystem.
Wrap-Up
To recap: When Python processes from A import B, it:
- Loads A as a
moduleobject (whether it’s a package or regular module). - Looks up B in A’s namespace, with minor differences in how it handles sub-modules if A is a package.
Packages aren’t a separate "type" to the interpreter—they’re just modules with extra tools to manage nested code.
内容的提问来源于stack exchange,提问作者zell

