import *" 究竟导入了什么?

69 投票
6 回答
117792 浏览
提问于 2025-04-15 19:53

在Python中,import *到底导入了什么呢?它会导入包含文件夹里的__init__.py吗?

举个例子,是否需要写from project.model import __init__,还是说from project.model import *就够了?

6 个回答

6

这里有一个很好的方法,可以查看星号(*)从一个模块中导入了哪些内容:

before = dir()
from math import *
after = dir()
print(set(after) - set(before))

返回结果是:

{'modf', 'pow', 'erfc', 'copysign', 'sqrt', 'atan2', 'e', 'tanh', 'pi', 'factorial', 'cosh', 'expm1', 'cos', 'fmod', 'frexp', 'log', 'acosh', 'sinh', 'floor', 'isclose', 'lgamma', 'ceil', 'gcd', 'ldexp', 'hypot', 'radians', 'atan', 'isnan', 'atanh', 'before', 'isinf', 'fabs', 'isfinite', 'log10', 'nan', 'tau', 'acos', 'gamma', 'asin', 'log2', 'tan', 'degrees', 'asinh', 'erf', 'fsum', 'inf', 'exp', 'sin', 'trunc', 'log1p'}

我在使用自己的模块时,都是明确地导入每一个内容,但要导入的东西列表变得太长了。所以,我不得不使用这个方法来获取星号导入的内容列表。

15

当你导入一个模块(或包)时,它会把模块里在__all__属性中列出的名字导入到当前的命名空间。如果没有这个属性,它会导入所有不以_开头的名字。

这个功能主要是为了在交互式解释器中方便使用:正如其他回答所提到的,不要在程序中使用它。

根据谷歌的Python风格指南,我建议只导入模块而不是从模块中导入类或函数(或其他名字)。这样做可以让代码更清晰、更准确,避免在导入“模块内部的东西”时可能遇到的微妙问题。

导入一个包(或包中的任何东西)时,会自动加载并执行包里的__init__.py文件——这个文件定义了包的内容。不过,它不会在你的当前命名空间中绑定__init__这个名字(所以从这个意义上说,它并没有导入这个名字)。

77

使用 from xyz import * 这种方式导入的“好处”是,它可以从指定的模块中导入几乎所有的东西(当然,几乎是指几乎所有... [见下面(a)的说明])。这样一来,你就可以直接使用导入模块里的各种对象(比如变量、类、方法等),而不需要在前面加上模块的名字。举个例子:

>>> from math import *
>>>pi
3.141592653589793
>>>sin(pi/2)
>>>1.0

不过,这种把所有东西都导入当前命名空间的做法是被不推荐的,原因有:

  • 可能会导致命名冲突(比如你在导入之前就有一个叫 pi 的变量)
  • 如果导入的对象数量很大,可能会效率低下
  • 没有明确记录变量、方法或类的来源(这样在以后查看代码时就不太方便了)

所以通常我们会把这种导入 * 的做法限制在临时测试等场合。正如 @Denilson-Sá-Maia 指出的,有些库(比如 pygame)有一个子模块,里面定义了最常用的常量和函数,这些子模块实际上是专门设计成可以用 import * 导入的。除了这些特殊的子模块,通常更好的做法是:

只明确导入几个对象

>>>from math import pi
>>>pi
>>>3.141592653589793
>>> sin(pi/2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'sin' is not defined

或者 将模块按其自己的命名空间导入(或者用别名,特别是当模块名很长,并且程序多次引用它的对象时)

  >>>import math
  >>>math.pi
  >>>3.141592653589793
  etc..


  >>>import math as m  #bad example math being so short and standard...
  >>>m.pi
  >>>3.141592653589793
  etc..

可以查看 Python 文档关于这个主题的说明

(a) 具体来说,使用 from xyz import * 导入了什么?
如果 xyz 模块定义了一个 __all__ 变量,它会导入这个序列中定义的所有名称;否则,它会导入所有名称,但不包括那些以下划线开头的名称。

注意 许多库都有子模块。例如,标准库 urllib 包含了像 urllib.requesturllib.errorsurllib.response 等子模块。一个常见的误解是:

from urllib import *

会导入所有这些子模块。其实并不是这样:你需要单独明确导入这些子模块,比如用 from urllib.request import * 等等。顺便说一下,这并不是 import * 特有的,普通的 import 也不会导入子模块(当然,* 通常是“所有”的简写,可能会误导人们以为所有子模块和其他所有东西都会被导入)。

撰写回答