ChatGPT解决这个技术问题 Extra ChatGPT

使用“导入模块”还是“从模块导入”?

我试图找到一份关于最好使用 import module 还是 from module import 的综合指南。我刚刚开始使用 Python,并且正在尝试从最佳实践入手。

基本上,我希望是否有人可以分享他们的经验,其他开发人员有什么偏好以及避免任何问题的最佳方法是什么?

我只是想让你知道,选择的答案是错误的。它指出差异是主观的,而存在差异。这可能会导致难以检测到错误。请参阅 Michael Ray Lovetts 的回答。
导入特定命名标识符 'from module import X,Y,Z'from module import * 之间存在天壤之别。后者会污染您的命名空间,并且可能会根据模块中发生的情况给出不可预测的结果。更糟糕的是使用多个模块执行 from module import *
Python 语言没有标准,但有一本不错的书,来自 Python 3.*,主要是由 Gvinno Van Rossum(该语言的作者)最初编写的 Python 参考:docs.python.org/3/tutorial
有关导入系统如何工作的详细而完整的描述,您可以阅读 docs.python.org/3/reference/index.html 中的专门部分,具体而言,它是:docs.python.org/3/reference/import.html

N
NullUserException

import modulefrom module import foo 之间的区别主要是主观的。选择您最喜欢的一个,并在使用时保持一致。这里有一些要点可以帮助您做出决定。

import module

优点:对导入语句的维护更少。不需要添加任何额外的导入来开始使用模块中的另一个项目

减少对导入语句的维护。不需要添加任何额外的导入来开始使用模块中的另一个项目

缺点:在您的代码中键入 module.foo 可能是乏味和冗余的(可以通过使用 import module as mo 然后键入 mo.foo 来最小化乏味)

在您的代码中输入 module.foo 可能是乏味且多余的(可以通过使用 import module as mo 然后输入 mo.foo 来最小化乏味)

from module import foo

优点:使用 foo 的输入更少 更多地控制可以访问模块的哪些项目

减少打字以使用 foo

更好地控制可以访问模块的哪些项目

缺点:要使用模块中的新项目,您必须更新导入语句您丢失了有关 foo 的上下文。例如,与 math.ceil() 相比,ceil() 的作用不太清楚

要使用模块中的新项目,您必须更新导入语句

你失去了关于 foo 的上下文。例如,与 math.ceil() 相比,ceil() 的作用不太清楚

任何一种方法都可以接受,但不要使用 from module import *

对于任何合理的大型代码集,如果您import *,您可能会将其固定到模块中,无法删除。这是因为很难确定代码中使用的哪些项目来自“模块”,因此很容易达到您认为不再使用 import 但很难确定的地步.


+1 不鼓励使用“from module import *”,它只会使命名空间变得混乱。
使命名空间混乱并不是“import *”中最成问题的部分,而是可读性的降低:任何名称冲突都会在(单元)测试中显示出来。但是您从导入的模块中使用的所有名称都将是空的,没有任何提示它们来自。我绝对讨厌“import *”。
Python之禅不是说显式优于隐式吗?
from module import * 可能特别有用,如果将其用作:if(windows):\n\t from module_win import * \n else: \n\t from module_lin import *。那么你的父模块可能包含独立于操作系统的函数名,如果 module_lin & module_win 具有相同的名称。这就像有条件地继承任一类。
@anishsane。还有另一种方法。导入 module_win 作为东西。然后总是使用 something.method_name()
m
martineau

这里还有一个未提及的细节,与写入模块有关。当然,这可能不是很常见,但我不时需要它。

由于引用和名称绑定在 Python 中的工作方式,如果您想从该模块外部更新模块中的某些符号,例如 foo.bar,并让其他导入代码“看到”该更改,则必须导入 foo a某种方式。例如:

模块 foo:

bar = "apples"

模块一:

import foo
foo.bar = "oranges"   # update bar inside foo module object

模块 b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

但是,如果您导入符号名称而不是模块名称,这将不起作用。

例如,如果我在模块 a 中执行此操作:

from foo import bar
bar = "oranges"

a 之外的任何代码都不会将 bar 视为“橙子”,因为我对 bar 的设置仅影响了模块 a 内的名称“bar”,它没有“触及”foo 模块对象,并且更新其 bar


不,在最后一个示例中,名称 'foo' 是未知的
这个答案提供了关于这个问题的“真实”答案:两个导入变体之间有什么区别
写了一些片段来证明这个答案是绝对正确的,但这背后的理由是什么?
这并不完全正确。所示的情况是字符串不可变的结果。如果"bar" 是一个列表,那么在模块 a 中说 "foo.bar.append('oranges')" 将在模块 b 中打印列表时反映出来。
@gateway2745 完全正确。这仅仅是阴影的一个例子。需要 global 的函数有同样的问题。
T
Tiago Martins Peres

尽管很多人已经解释了 importimport from,但我想尝试更多地解释一下幕后发生的事情,以及它改变的所有地方。

导入 foo:

导入 foo,并在当前命名空间中创建对该模块的引用。然后,您需要定义完整的模块路径以从模块内部访问特定的属性或方法。

例如 foo.bar 但不是 bar

从 foo 导入栏:

导入 foo,并创建对所有列出的成员 (bar) 的引用。不设置变量 foo

例如 bar 但不是 bazfoo.baz

从 foo 导入 *:

导入 foo,并创建对该模块在当前命名空间中定义的所有公共对象的引用(如果 __all__ 存在,则在 __all__ 中列出的所有对象,否则不以 _ 开头的所有对象)。不设置变量 foo

例如 barbaz 但不是 _quxfoo._qux

现在让我们看看我们何时执行 import X.Y

>>> import sys
>>> import os.path

使用名称 osos.path 检查 sys.modules

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

使用 osos.path 检查 globals()locals() 命名空间字典:

>>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>

从上面的例子中我们发现在本地和全局命名空间中只插入了 os。所以,我们应该可以使用:

>>> os
<module 'os' from
  '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> os.path
<module 'posixpath' from
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

但不是path

>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

从 locals() 命名空间中删除 os 后,您将无法访问 osos.path,即使它们存在于 sys.modules 中:

>>> del locals()['os']
>>> os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

现在让我们谈谈从以下位置导入:

从:

>>> import sys
>>> from os import path

使用 os 和 os.path 检查 sys.modules:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

我们发现在 sys.modules 中我们发现与使用 import name 之前所做的相同

好的,让我们看看它在 locals()globals() 命名空间字典中的样子:

>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>

您可以使用名称 path 而不是 os.path 访问:

>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

让我们从 locals() 中删除“路径”:

>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

最后一个使用别名的示例:

>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

并且没有定义路径:

>>> globals()['path']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>

虽然这很冗长,但对于一个相当复杂的问题,这确实是列表中的最佳答案。它提供了实际代码来帮助解释对于这个特定问题的“幕后”微妙之处,这些细节比风格更重要。我希望我能不止一次地投票!
使用 as SYMBOL 会改变这个答案的工作方式吗?
d
dr_

两种方式都得到支持是有原因的:有时一种方式比另一种更合适。

导入模块:当您使用模块中的许多位时很好。缺点是您需要使用模块名称限定每个引用。

from module import ...:很高兴导入的项目无需模块名称前缀即可直接使用。缺点是你必须列出你使用的每一个东西,而且在代码中并不清楚某些东西是从哪里来的。

使用哪个取决于哪个使代码清晰易读,并且与个人喜好有很大关系。我倾向于 import module 通常是因为在代码中非常清楚对象或函数的来源。当我在代码中使用一些对象/函数时,我会使用 from module import ...


有没有办法使用 from M import X 并且仍然以某种方式获得使用限定符的好处?如果您在导入之后M.X仍能做到这一点,那么您似乎可以两全其美。
@artgropod:有点。你可以做class m: from something.too.long import x, y, z。不过真的不建议这样做。
S
Stefano Borini

我个人总是使用

from package.subpackage.subsubpackage import module

然后访问所有内容

module.function
module.modulevar

等等。原因是同时您的调用时间很短,并且您清楚地定义了每个例程的模块名称空间,如果您必须在源代码中搜索给定模块的用法,这将非常有用。

不用说,不要使用 import *,因为它会污染你的命名空间,并且它不会告诉你给定函数来自哪里(来自哪个模块)

当然,如果两个不同包中的两个不同模块的模块名称相同,则可能会遇到麻烦,例如

from package1.subpackage import module
from package2.subpackage import module

在这种情况下,你当然会遇到麻烦,但是强烈暗示你的包布局有缺陷,你必须重新考虑它。


在最后一种情况下,您始终可以使用: import pkgN.sub.module as modN 为每个模块提供不同的名称。您还可以使用“import modulename as mod1”模式来缩短长名称,或者通过一个名称更改在相同 API(例如 DB API 模块)的实现之间切换。
当你使用 pathlib 时,你总是写成 pathlib.Path 吗?
A
Andrew Hare
import module

当您将使用模块中的许多功能时最好。

from module import function

当您只需要 function 时,最好避免使用模块中的所有函数和类型污染全局命名空间。


如果你做'import module',全局命名空间中唯一的东西肯定是'module'吗?如果你执行'from .. import *',你只会污染命名空间。
J
Jan Wrobel

我刚刚发现了这两种方法之间的另一个细微差别。

如果模块 foo 使用以下导入:

from itertools import count

然后模块 bar 可能会错误地使用 count,就好像它是在 foo 中定义的,而不是在 itertools 中定义的:

import foo
foo.count()

如果 foo 使用:

import itertools

错误仍然是可能的,但不太可能发生。 bar 需要:

import foo
foo.itertools.count()

这给我带来了一些麻烦。我有一个模块错误地从一个没有定义它的模块导入了一个异常,只从其他模块导入了它(使用 from module import SomeException)。当不再需要并删除导入时,有问题的模块被破坏了。


u
user2141737

这是另一个没有提到的区别。这是从 http://docs.python.org/2/tutorial/modules.html 逐字复制的

请注意,使用时

from package import item

item 可以是包的子模块(或子包),也可以是包中定义的其他名称,如函数、类或变量。 import 语句首先测试该项目是否在包中定义;如果不是,它假定它是一个模块并尝试加载它。如果找不到它,则会引发 ImportError 异常。

相反,当使用类似的语法时

import item.subitem.subsubitem

除最后一项外,每一项都必须是一个包裹;最后一项可以是模块或包,但不能是前一项中定义的类或函数或变量。


我注意到的另一件事是,如果 item 也是包内的子模块,则“从包导入项”有效,但“导入包”package.item.subitem=... 不适用于空的 init.py 包,除非我们在包的初始化文件中有“导入项目”。
C
Community

由于我也是初学者,所以我将尝试以一种简单的方式来解释这一点:在 Python 中,我们有三种类型的 import 语句,它们是:

1. 通用进口:

import math

这种类型的导入是我个人最喜欢的,这种导入技术的唯一缺点是,如果您需要使用任何模块的功能,您必须使用以下语法:

math.sqrt(4)

当然,它会增加打字工作量,但作为初学者,它将帮助您跟踪与之相关的模块和功能,(一个好的文本编辑器会显着减少打字工作量,推荐)。

使用以下 import 语句可以进一步减少打字工作:

import math as m

现在,您可以使用 m.sqrt(),而不是使用 math.sqrt()

2.函数导入:

from math import sqrt

如果您的代码只需要访问模块中的单个或几个函数,则这种类型的导入最适合,但是对于使用模块中的任何新项目,您必须更新导入语句。

3.通用进口:

from math import * 

虽然它显着减少了输入工作,但不推荐使用,因为它会使用模块中的各种函数填充您的代码,并且它们的名称可能与用户定义函数的名称冲突。例子:

如果你有一个名为 sqrt 的函数并导入 math,你的函数是安全的:有你的 sqrt 和 math.sqrt。但是,如果您使用 from math import *,则会出现问题:即,两个不同的函数具有完全相同的名称。资料来源:Codecademy


i
indivisibleatom
import package
import module

对于 import,令牌必须是模块(包含 Python 命令的文件)或包(sys.path 中包含文件 __init__.py 的文件夹。)

当有子包时:

import package1.package2.package
import package1.package2.module

文件夹(包)或文件(模块)的要求相同,但文件夹或文件必须在 package2 内,必须在 package1 内,并且 package1package2 都必须包含 __init__.py 文件. https://docs.python.org/2/tutorial/modules.html

使用 from 样式的导入:

from package1.package2 import package
from package1.package2 import module

包或模块以 module(或 package)而不是 package1.package2.module 的形式进入包含 import 语句的文件的命名空间。您始终可以绑定到更方便的名称:

a = big_package_name.subpackage.even_longer_subpackage_name.function

只有 from 样式的导入允许您命名特定的函数或变量:

from package3.module import some_function

是允许的,但是

import package3.module.some_function 

不被允许。


D
DNS

补充一下人们对 from x import * 的看法:除了让人们更难分辨名称的来源之外,这还会让 Pylint 等代码检查器失效。他们会将这些名称报告为未定义的变量。


M
MarianD

这是我当前目录的目录结构:

. └─a └─b └─c

import 语句会记住所有中间名。这些名称必须经过限定: In[1]: import abc In[2]: a Out[2]: In[3]: ab Out[3]: In[4]: abc Out[4]: from ... import ... 语句只记住导入的名称。此名称不得限定: In[1]: from ab import c In[2]: a NameError: name 'a' is not defined In[2]: ab NameError: name 'a' is not defined In[3] : abc NameError: name 'a' is not defined In[4]: c Out[4]:

注意:当然,我在第 1 步和第 2 步之间重新启动了 Python 控制台。


S
SingleNegationElimination

我自己对此的回答主要取决于首先,我将使用多少个不同的模块。如果我只打算使用一两个,我会经常使用 from ... import,因为它可以减少其余部分的击键次数文件,但如果我要使用许多不同的模块,我更喜欢 import 因为这意味着每个模块引用都是自记录的。我可以看到每个符号的来源,而无需四处寻找。

通常我更喜欢普通导入的自我记录风格,并且只有在我必须输入模块名称的次数超过 10 到 20 时才更改为 from.. import,即使只有一个模块被导入。


a
ahfx

我想补充一点。如果遇到循环导入,了解 Python 如何将导入的模块作为属性处理会很有用。

我有以下结构:

mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py

从 main.py 我将使用不同的导入方法导入其他模块

主要.py:

import mod.a
import mod.b as b
from mod import c
import d

dis.dis 显示了差异(注意模块名称,abcd):

  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (mod.a)
              9 STORE_NAME               1 (mod)

  2          12 LOAD_CONST               0 (-1)
             15 LOAD_CONST               1 (None)
             18 IMPORT_NAME              2 (b)
             21 STORE_NAME               2 (b)

  3          24 LOAD_CONST               0 (-1)
             27 LOAD_CONST               2 (('c',))
             30 IMPORT_NAME              1 (mod)
             33 IMPORT_FROM              3 (c)
             36 STORE_NAME               3 (c)
             39 POP_TOP

  4          40 LOAD_CONST               0 (-1)
             43 LOAD_CONST               1 (None)
             46 IMPORT_NAME              4 (mod.d)
             49 LOAD_ATTR                5 (d)
             52 STORE_NAME               5 (d)
             55 LOAD_CONST               1 (None)

最后它们看起来是一样的(STORE_NAME 是每个示例中的结果),但是如果您需要考虑以下四个循环导入,请注意这一点:

示例1

foo/
   __init__.py
   a.py
   b.py
a.py:
import foo.b 
b.py:
import foo.a
>>> import foo.a
>>>

这有效

示例2

bar/
   __init__.py
   a.py
   b.py
a.py:
import bar.b as b
b.py:
import bar.a as a
>>> import bar.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bar\a.py", line 1, in <module>
    import bar.b as b
  File "bar\b.py", line 1, in <module>
    import bar.a as a
AttributeError: 'module' object has no attribute 'a'

没有骰子

示例3

baz/
   __init__.py
   a.py
   b.py
a.py:
from baz import b
b.py:
from baz import a
>>> import baz.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "baz\a.py", line 1, in <module>
    from baz import b
  File "baz\b.py", line 1, in <module>
    from baz import a
ImportError: cannot import name a

类似的问题......但显然 from x import y 与 import import xy as y 不同

例子4

qux/
   __init__.py
   a.py
   b.py
a.py:
import b 
b.py:
import a
>>> import qux.a
>>>

这个也有效


惊人的有趣事实!你能解释一下这背后的原因吗?
好问题!我不知道我脑海中的答案,但这听起来像是一个有趣的通过 python 内部探索的练习。
S
Saurav Sahu

我发现令人惊讶地没有人谈论的显着差异之一是,使用普通 import 您可以从导入的模块访问 private variableprivate functionsfrom-import 语句无法做到这一点。

https://i.stack.imgur.com/1fqOd.png

图片中的代码:

设置.py

public_variable = 42
_private_variable = 141
def public_function():
    print("I'm a public function! yay!")
def _private_function():
    print("Ain't nobody accessing me from another module...usually")

plain_importer.py

import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()

# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually

from_importer.py

from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function()   #doesn't work

m
matheburg

正如 Jan Wrobel 所提到的,不同进口的一个方面是进口的披露方式。

模块之谜

from math import gcd
...

神话的使用:

import mymath
mymath.gcd(30, 42)  # will work though maybe not expected

如果我导入 gcd 只是为了内部使用,而不是向 mymath 的用户透露,这可能会很不方便。我经常遇到这种情况,在大多数情况下,我想“保持我的模块干净”。

除了 Jan Wrobel 建议使用 import math 来掩盖这一点之外,我还开始通过使用前导下划线来隐藏导入:

# for instance...
from math import gcd as _gcd
# or...
import math as _math

在较大的项目中,这种“最佳实践”允许我准确控制向后续导入披露的内容和不披露的内容。这使我的模块保持清洁并在一定规模的项目中得到回报。


M
M_x

因为很多人在这里回答,但我只是尽力而为:)

当您不知道必须从模块导入哪个项目时,导入模块是最好的。这样在出现问题时可能很难调试,因为您不知道哪个项目有问题。当您知道需要导入哪个项目并且根据您的需要使用导入特定项目进行更多控制时,form module import 是最好的。使用这种方式调试可能很容易,因为您知道您导入了哪个项目。


C
Chris Collett

有很多答案,但没有一个提到测试(使用 unittestpytest)。

tl;博士

import foo 用于外部模块以简化测试。

艰难的道路

从模块中单独导入类/函数 (from foo import bar) 会使红绿重构周期变得乏味。例如,如果我的文件看起来像

# my_module.py

from foo import bar


class Thing:
    def do_thing(self):
        bar('do a thing')

我的测试是

# test_my_module.py

from unittest.mock import patch
import my_module


patch.object(my_module, 'bar')
def test_do_thing(mock_bar):
    my_module.Thing().do_thing()
    mock_bar.assert_called_with('do a thing')

乍一看,这似乎很棒。但是如果我想在不同的文件中实现 Thing 类会发生什么?我的结构必须像这样改变......

# my_module.py

from tools import Thing


def do_thing():
    Thing().do_thing()


# tools.py

from foo import bar


class Thing:
    def do_thing(self):
        bar('do a thing')


# test_my_module.py

from unittest.mock import patch
import my_module
import tools  # Had to import implementation file...


patch.object(tools, 'bar')  # Changed patch
def test_do_thing(mock_bar):
    my_module.do_thing()  # Changed test (expected)
    mock_bar.assert_called_with('do a thing')

不幸的是,由于我使用了 from foo import bar,我需要更新我的补丁以引用 tools 模块。本质上,由于我的测试对实现了解太多,因此需要进行比预期更多的更改才能进行此重构。

更好的方法

使用 import foo,我的测试可以忽略模块的实现方式,只需修补整个模块。

# my_module.py

from tools import Thing


def do_thing():
    Thing().do_thing()


# tools.py

import foo


class Thing:
    def do_thing(self):
        foo.bar('do a thing')  # Specify 'bar' is from 'foo' module


# test_my_module.py

from unittest.mock import patch
import my_module


patch('foo')  # Patch entire foo module
def test_do_thing(mock_foo):
    my_module.do_thing()  # Changed test (expected)
    mock_foo.bar.assert_called_with('do a thing')

你的测试知道的实现细节越少越好。这样,如果您想出更好的解决方案(使用类而不是函数,使用附加文件来分隔想法等),则需要在测试中进行较少更改以适应重构。


D
Dlucidone

导入模块 - 您不需要额外的努力来从模块中获取另一个东西。它有诸如冗余打字等缺点

模块导入自 - 更少输入和更多控制可以访问模块的哪些项目。要使用模块中的新项目,您必须更新导入语句。


J
Jeyekomon

有一些内置模块主要包含裸函数(base64mathosshutilsystime、...),拥有这些裸函数绝对是一个好习惯函数绑定到某个命名空间,从而提高代码的可读性。考虑一下在没有命名空间的情况下理解这些函数的含义是多么困难:

copysign(foo, bar)
monotonic()
copystat(foo, bar)

比它们绑定到某个模块时:

math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)

有时您甚至需要命名空间来避免不同模块之间的冲突(json.loadpickle.load

配置解析器

约会时间

临时文件

压缩文件

configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()

因此,在代码中使用这些带有附加模块命名空间的类是否会添加一些新信息或只是延长代码可能会存在争议。


y
yoonghm

我正在回答一个类似的问题帖子,但在我发布之前,海报将其删除。这里有一个例子来说明差异。

Python 库可能有一个或多个文件(模块)。例如,

package1
  |-- __init__.py

或者

package2
  |-- __init__.py
  |-- module1.py
  |-- module2.py

我们可以在任何基于设计要求的文件中定义 python 函数或类。

让我们定义

mylibrary1 下的 __init__.py 中的 func1() 和 mylibrary2 下的 module2.py 中的 foo()。

我们可以使用其中一种方法访问 func1()

import package1

package1.func1()

或者

import package1 as my

my.func1()

或者

from package1 import func1

func1()

或者

from package1 import *

func1()

我们可以使用以下方法之一访问 foo()

import package2.module2

package2.module2.foo()

或者

import package2.module2 as mod2

mod2.foo()

或者

from package2 import module2

module2.foo()

或者

from package2 import module2 as mod2

mod2.foo()

或者

from package2.module2 import *

foo()

S
Satish Chandra Gupta

简而言之,这完全是为了方便程序员。在核心级别,它们只是导入模块的所有功能。

import module:当您使用 import module 时,要使用此模块的方法,您必须编写 module.method()。每次使用任何方法或属性时,都必须引用该模块。

from module import all:当您使用 from module import all 而不是使用此模块的方法时,您只需编写 method() 而无需引用该模块。