首页 文章

使用'import module'或'from module import'?

提问于
浏览
279

我试图找到一个关于是否最好使用 import modulefrom module import 的综合指南?我试着从最好的做法开始.665752_m

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

13 回答

  • 5

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

    import module

    • Pros:

    • 减少 import 陈述的维护 . 不需要添加任何其他导入即可开始使用模块中的其他项目

    • Cons:

    • 在代码中输入 module.foo 可能很乏味且冗余(使用 import module as mo 然后输入 mo.foo 可以最小化单调)

    from module import foo

    • Pros:

    • 减少输入使用 foo

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

    • Cons:

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

    • 你丢失了关于 foo 的背景信息 . 例如,与 math.ceil() 相比, ceil() 的作用还不太清楚

    两种方法都可以接受,但 don't 使用 from module import * .

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

  • 83

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

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

    模块foo:

    bar = "apples"
    

    模块a:

    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为“oranges”,因为我的bar设置只影响了模块a中的名称“bar”,它没有“到达”foo模块对象并更新其“bar” .

  • 4

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


    import foo:

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

    例如 . foo.bar 但不是 bar

    来自foo导入栏的

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

    例如 . bar 但不是 bazfoo.baz

    来自foo import *的

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

    例如 . barbaz 但不是 _quxfoo._qux .


    现在让我们看看 import X.Y

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

    检查名称为 osos.pathsys.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() 命名空间dicts:

    >>> 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 后,即使它们存在于sys.modules中,您也无法访问 os 以及 os.path

    >>> 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() 开始's delete ' path':

    >>> 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'
    >>>
    
  • 7

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

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

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

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

  • 12

    我个人经常使用

    from package.subpackage.subsubpackage import module
    

    然后访问所有内容

    module.function
    module.modulevar
    

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

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

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

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

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

  • 349
    import module
    

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

    from module import function
    

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

  • 38

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

    请注意,使用时

    from package import item
    

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

    相反,使用语法时

    import item.subitem.subsubitem
    

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

  • 0

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

    如果模块 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 ) . 当不再需要和删除导入时,违规模块被破坏 .

  • 4

    为了增加人们对 from x import * 所说的内容:除了让人们更难分辨姓名来自何处之外,这还会抛出像Pylint这样的代码检查器 . 他们会将这些名称报告为未定义的变量 .

  • 45
    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
    

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

    a = big_package_name.subpackage.even_longer_subpackage_name.function
    

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

    from package3.module import some_function
    

    是允许的,但是

    import package3.module.some_function
    

    不被允许 .

  • 3

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

    Usuaully我更喜欢普通导入的自我记录样式,只有当我输入模块名称的次数增加到10到20以上时,才会改为从...导入,即使只导入了一个模块 .

  • 2

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

    1. Generic imports:

    import math
    

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

    math.sqrt(4)
    

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

    Typing effort can be further reduced by using this import statement:

    import math as m
    

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

    2. Function imports:

    from math import sqrt
    

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

    3. Universal imports:

    from math import
    

    虽然它可以显着减少打字工作但不建议使用,因为它会使用模块中的各种函数填充代码,并且它们的名称可能与用户定义函数的名称冲突 . example:

    如果你有自己名为sqrt的函数并导入数学,那么你的函数是安全的:有你的sqrt并且有math.sqrt . 但是,如果您使用math import *,则会出现问题:即两个具有完全相同名称的不同函数 . 来源:Codecademy

  • 30

    导入模块 - 您不需要额外的工作来从模块中获取另一个东西 . 它有诸如冗余打字之类的缺点

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

相关问题