使用'导入模块'或'从模块导入'?

Fil*_*vić 370 python python-import

我试图找到一个关于是否最好使用的综合指南import modulefrom module import?我刚刚开始使用Python,我试图从最初的实践开始.

基本上,我希望如果有人能分享他们的经验,有什么喜好其他开发商,什么是避免任何的最好办法陷阱的道路?

Mar*_*ddy 426

import module和之间的区别from module import foo主要是主观的.选择你最喜欢的那个,并在使用它时保持一致.以下是一些可以帮助您做出决定的要点.

import module

  • 优点:
    • 减少对import陈述的维护.不需要添加任何其他导入即可开始使用模块中的其他项目
  • 缺点:
    • 输入module.foo您的代码可能是乏味和冗余的(通过使用import module as mo然后键入可以最小化乏味mo.foo)

from module import foo

  • 优点:
    • 减少使用的输入 foo
    • 可以更好地控制可以访问模块的哪些项目
  • 缺点:
    • 要使用模块中的新项目,您必须更新import语句
    • 你失去了关于的背景foo.例如,与之ceil()相比,它不太清楚math.ceil()

这两种方法都可以接受,但不要使用from module import *.

对于任何合理的大量代码,如果您import *将可能将其粘合到模块中,则无法将其删除.这是因为很难确定代码中使用的项目来自"模块",这使得很容易达到您认为不再使用import它的程度,但是很难确定.

  • +1阻止使用"from module import*",它只会使命名空间变得混乱. (61认同)
  • 混淆命名空间不是*import*中最有问题的部分,它是可读性的降低:任何名称冲突都会在(单元)测试中显示出来.但是你从导入的模块中使用的所有名称都是裸露的,并且它们来自于它们.我绝对不喜欢"进口*". (19认同)
  • Python的Zen说明文是否比隐含更好? (19认同)
  • @anishsane.还有另外一种方法.将module_win导入为某事.然后总是使用something.method_name() (17认同)
  • `from module import*`可能特别有用,如果使用它:`if(windows):\n\t来自module_win import*\n else:\n\t来自module_lin import*`.然后,如果module_lin和module_win中的函数名称具有相同的名称,则父模块可能包含与OS无关的函数名称.这就像有条件地继承任何一个类. (8认同)
  • "来自模块导入foo"的另一个专家:**宣布弱依赖**.当你需要一个不在标准库中的模块时,只需要一个小foo,这表明后代可以通过重构foo的使用来消除依赖. (5认同)
  • -1这个答案错了​​.它们是有区别的.请参阅@Michael Ray Lovetts回答真实答案.有一个**关键的**差异! (3认同)
  • -1:区别主要不是主观的。实际上,在某些情况下,它会更改语义。(这是事实,尽管我不知道为什么会这样工作。)请参见以下示例示例:http://stackoverflow.com/a/20863145/1143274 (2认同)
  • 一个语义差异是对于不可变对象,`from mod import foo` 创建一个新的 `foo`,而 `import mod; mod.foo` 使用与 `mod` 中相同的 `foo` 对象。但是无论如何,`foo` 应该隐藏在访问器后面。 (2认同)
  • @Rightleg 我见过`import tkinter as tk`,也许这可以回答你的问题? (2认同)
  • 它对导入的模块的大小有什么影响吗?当我编译我的源文件时,如果我想让它更小,导入一种或另一种方式是否相同? (2认同)

Mic*_*ett 127

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

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

模块foo:

bar = "apples"
Run Code Online (Sandbox Code Playgroud)

模块a:

import foo
foo.bar = "oranges"   # update bar inside foo module object
Run Code Online (Sandbox Code Playgroud)

模块b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"
Run Code Online (Sandbox Code Playgroud)

但是,如果导入符号名称而不是模块名称,则不起作用.

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

from foo import bar
bar = "oranges"
Run Code Online (Sandbox Code Playgroud)

在a之外没有代码会看到bar为"oranges",因为我的bar设置只影响了模块a中的名称"bar",它没有"到达"foo模块对象并更新其"bar".

  • 这个答案提供了关于这个问题的"真实"答案:两种导入变体之间的区别是什么 (22认同)
  • 不,在最后一个例子中,名称'foo'是未知的 (4认同)
  • 写了一些片段来证明这个答案是绝对正确的,但这背后的理由是什么? (3认同)
  • 这并不完全正确。所示的情况是字符串不可变的结果。如果“bar”是一个列表,那么在模块 a 中说“foo.bar.append('oranges')”,在模块 b 中打印列表时将会反映出来。 (2认同)
  • @gateway2745 完全正确。这只是阴影的一个例子。需要“全局”的函数也有同样的问题。 (2认同)
  • 尽管我同意这个答案的技术性,但我想指出这是一个不好的做法。您应该*尽可能*避免更改全局变量,以避免很难找到错误。多个模块更改全局变量会呈指数级增加这种风险。请永远不要这样做。 (2认同)
  • 这是非常重要的。另外@ChrisCollett 答案很有帮助,因为在不知道全局更改模块的情况下,您可能会在不知道的情况下全局更改模块。所以答案帮助我停止全局更改模块。 (2认同)
  • @rohit_r我认为这与对象的不变性无关。如果你这样做了 `bar = [1,2,3]` 也不会反映在模块 b 或 foo 中。这实际上是因为“from foo import bar”导入的“bar”实际上是对模块 foo 中对象的新引用,并且赋值仅覆盖本地引用,同时保持模块 foo 中的对象不变。 (2认同)

Jam*_*pam 71

虽然很多人已经解释过importvs import from,但是我想尝试更多地解释一下在幕后发生的事情,以及它所改变的所有地方.


import foo:

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

例如,foo.bar但不bar

from foo import bar:

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

例如bar但不是bazfoo.baz

from foo import *:

导入foo,并创建对当前命名空间中该模块定义的所有公共对象的引用(__all__if __all__exists中列出的所有内容,否则不是以所有内容开头_).不设置变量foo.

barbaz而不是_quxfoo._qux.


现在让我们看看我们做什么import X.Y:

>>> import sys
>>> import os.path
Run Code Online (Sandbox Code Playgroud)

检查sys.modules姓名osos.path:

>>> 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'>
Run Code Online (Sandbox Code Playgroud)

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

 >>> 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'
>>>
Run Code Online (Sandbox Code Playgroud)

从上面的例子中我们发现只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'>
 >>>
Run Code Online (Sandbox Code Playgroud)

但不是path.

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

一旦你删除os从当地人()命名空间,您将无法访问os,以及os.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
>>>
Run Code Online (Sandbox Code Playgroud)

现在我们来谈谈import from:

from:

>>> import sys
>>> from os import path
Run Code Online (Sandbox Code Playgroud)

检查sys.modulesosos.path:

>>> 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'>
Run Code Online (Sandbox Code Playgroud)

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

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

>>> 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'
>>>
Run Code Online (Sandbox Code Playgroud)

您可以使用名称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
>>>
Run Code Online (Sandbox Code Playgroud)

让我们删除'path' locals():

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

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

>>> 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'>
>>>
Run Code Online (Sandbox Code Playgroud)

并没有定义路径:

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

  • 虽然这很冗长,但对于一个相当复杂的问题,这确实是列表中的最佳答案.它提供了实际代码来帮助解释这个特定问题的"引擎盖下"细微之处,这些细微之处比风格更重要.我希望我能不止一次地投票! (6认同)

dwc*_*dwc 39

支持这两种方式的原因是:有时候一种方式比另一种方式更合适.

  • import module:当您使用模块中的许多位时很好.缺点是您需要使用模块名称限定每个引用.

  • from module import ...:很好,导入的项目可以直接使用,没有模块名称前缀.缺点是你必须列出你使用的每一件事,并且在代码中不清楚某些东西来自何处.

使用哪个取决于哪个使代码清晰可读,并且与个人偏好有很多关系.我倾向于import module普遍,因为在代码中,对象或函数的来源非常清楚.我用from module import ...的时候我使用了一些对象/功能一个不少的代码.


Ste*_*ini 34

我个人经常使用

from package.subpackage.subsubpackage import module
Run Code Online (Sandbox Code Playgroud)

然后访问所有内容

module.function
module.modulevar
Run Code Online (Sandbox Code Playgroud)

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

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

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

from package1.subpackage import module
from package2.subpackage import module
Run Code Online (Sandbox Code Playgroud)

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

  • 在最后一种情况下,您始终可以使用:import pkgN.sub.module作为modN,为每个模块提供不同的名称.您还可以使用"import modulename as mod1"模式来缩短长名称,或者使用单个名称更改在同一API(例如,DB API模块)的实现之间切换. (10认同)

And*_*are 15

import module
Run Code Online (Sandbox Code Playgroud)

最好何时使用模块中的许多功能.

from module import function
Run Code Online (Sandbox Code Playgroud)

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

  • 如果你做'导入模块',那么全局命名空间中唯一的东西就是'模块'?如果您执行'from .. import*',则只会污染命名空间. (7认同)

Jan*_*bel 9

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

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

from itertools import count
Run Code Online (Sandbox Code Playgroud)

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

import foo
foo.count()
Run Code Online (Sandbox Code Playgroud)

如果foo使用:

import itertools
Run Code Online (Sandbox Code Playgroud)

错误仍然存​​在,但不太可能发生.bar需要:

import foo
foo.itertools.count()
Run Code Online (Sandbox Code Playgroud)

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


小智 9

这是另一个未提及的差异.这是从http://docs.python.org/2/tutorial/modules.html逐字复制的

请注意,使用时

from package import item
Run Code Online (Sandbox Code Playgroud)

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

相反,使用语法时

import item.subitem.subsubitem
Run Code Online (Sandbox Code Playgroud)

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


ahf*_*hfx 7

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

我有以下结构:

mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py
Run Code Online (Sandbox Code Playgroud)

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

主要.py:

import mod.a
import mod.b as b
from mod import c
import d
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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

例子1

foo/
   __init__.py
   a.py
   b.py
Run Code Online (Sandbox Code Playgroud)
a.py:
import foo.b 
Run Code Online (Sandbox Code Playgroud)
b.py:
import foo.a
Run Code Online (Sandbox Code Playgroud)
>>> import foo.a
>>>
Run Code Online (Sandbox Code Playgroud)

这有效

例子2

bar/
   __init__.py
   a.py
   b.py
Run Code Online (Sandbox Code Playgroud)
a.py:
import bar.b as b
Run Code Online (Sandbox Code Playgroud)
b.py:
import bar.a as a
Run Code Online (Sandbox Code Playgroud)
>>> 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'
Run Code Online (Sandbox Code Playgroud)

没有骰子

例子3

baz/
   __init__.py
   a.py
   b.py
Run Code Online (Sandbox Code Playgroud)
a.py:
from baz import b
Run Code Online (Sandbox Code Playgroud)
b.py:
from baz import a
Run Code Online (Sandbox Code Playgroud)
>>> 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
Run Code Online (Sandbox Code Playgroud)

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

例子4

qux/
   __init__.py
   a.py
   b.py
Run Code Online (Sandbox Code Playgroud)
a.py:
import b 
Run Code Online (Sandbox Code Playgroud)
b.py:
import a
Run Code Online (Sandbox Code Playgroud)
>>> import qux.a
>>>
Run Code Online (Sandbox Code Playgroud)

这个也可以用

  • 惊人有趣的事实!您能解释一下这背后的原因吗? (2认同)

Ben*_*own 5

import package
import module
Run Code Online (Sandbox Code Playgroud)

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

有子包时:

import package1.package2.package
import package1.package2.module
Run Code Online (Sandbox Code Playgroud)

为文件夹(封装)或文件(模块)的要求是相同的,但该文件夹或文件必须是内部package2必须是内部package1,并且两个package1package2必须包含__init__.py文件。https://docs.python.org/2/tutorial/modules.html

具有from导入样式:

from package1.package2 import package
from package1.package2 import module
Run Code Online (Sandbox Code Playgroud)

程序包或模块将输入包含import语句的文件的名称空间用module(或package)代替package1.package2.module。您始终可以绑定到更方便的名称:

a = big_package_name.subpackage.even_longer_subpackage_name.function
Run Code Online (Sandbox Code Playgroud)

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

from package3.module import some_function
Run Code Online (Sandbox Code Playgroud)

被允许,但是

import package3.module.some_function 
Run Code Online (Sandbox Code Playgroud)

不允许。


Sha*_*wat 5

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

1.通用进口:

import math
Run Code Online (Sandbox Code Playgroud)

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

math.sqrt(4)
Run Code Online (Sandbox Code Playgroud)

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

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

import math as m
Run Code Online (Sandbox Code Playgroud)

现在,math.sqrt()可以使用代替使用m.sqrt()

2.函数导入:

from math import sqrt
Run Code Online (Sandbox Code Playgroud)

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

3.普遍进口:

from math import * 
Run Code Online (Sandbox Code Playgroud)

尽管它可以显着减少键入工作,但不建议这样做,因为它将用模块中的各种函数填充代码,并且它们的名称可能与用户定义函数的名称冲突。 例:

如果您有一个自己的名为sqrt的函数并且导入了数学运算,则该函数是安全的:存在您的sqrt和Math.sqrt。但是,如果从数学导入*中进行操作,则会遇到问题:即,两个具有相同名称的不同函数。资料来源:Codecademy


Mar*_*anD 5

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

\n\n
\n
.  \n\xe2\x94\x94\xe2\x94\x80a  \n   \xe2\x94\x94\xe2\x94\x80b  \n     \xe2\x94\x94\xe2\x94\x80c\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n
    \n
  1. import语句会记住所有中间名称
    \n这些名称必须经过限定:

    \n\n
    In[1]: import a.b.c\n\nIn[2]: a\nOut[2]: <module 'a' (namespace)>\n\nIn[3]: a.b\nOut[3]: <module 'a.b' (namespace)>\n\nIn[4]: a.b.c\nOut[4]: <module 'a.b.c' (namespace)>\n
    Run Code Online (Sandbox Code Playgroud)
  2. \n
  3. from ... import ...语句仅记住导入的名称
    \n此名称不得被限定:

    \n\n
    In[1]: from a.b import c\n\nIn[2]: a\nNameError: name 'a' is not defined\n\nIn[2]: a.b\nNameError: name 'a' is not defined\n\nIn[3]: a.b.c\nNameError: name 'a' is not defined\n\nIn[4]: c\nOut[4]: <module 'a.b.c' (namespace)>\n
    Run Code Online (Sandbox Code Playgroud)
  4. \n
\n\n
\n\n
    \n
  • 注意:当然,我在步骤 1 和 2 之间重新启动了 Python 控制台。
  • \n
\n