我试图找到一个全面的指南,是否最好使用导入模块或从模块导入。我刚刚开始学习Python,我正试图从最佳实践开始。

基本上,我希望任何人都能分享他们的经验,其他开发者有什么偏好,以及避免任何陷阱的最佳方法是什么?


当前回答

这里还有另一个细节,没有提到,与写入模块有关。虽然这可能不太常见,但我时不时地需要它。

由于Python中引用和名称绑定的工作方式,如果你想更新模块中的某个符号,请输入foo。Bar,从模块外部,并有其他导入代码“看到”的变化,你必须以某种方式导入foo。例如:

模块foo:

bar = "apples"

模块一:

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

模块2:

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

但是,如果你导入的是符号名而不是模块名,这就行不通了。

例如,如果我在模块a中这样做:

from foo import bar
bar = "oranges"

没有代码在一个外部将看到bar作为“橙子”,因为我的bar设置只是影响模块a中的名称“bar”,它没有“到达”foo模块对象并更新它的bar。

其他回答

我个人总是用

from package.subpackage.subsubpackage import module

然后访问所有

module.function
module.modulevar

等。原因是,与此同时,您可以进行简短的调用,并且可以清楚地定义每个例程的模块名称空间,如果您必须在源代码中搜索给定模块的使用情况,这是非常有用的。

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

当然,如果在两个不同的包中对两个不同的模块使用相同的模块名,您可能会遇到麻烦,例如

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

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

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

博士tl;

对外部模块使用import foo来简化测试。

艰难的方式

从模块中单独导入类/函数(从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,我需要更新我的补丁来引用工具模块。从本质上讲,由于我的测试对实现了解太多,因此要进行这个重构,需要更改的内容要比预期的多得多。

更好的方法

使用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')

测试知道的实现细节越少越好。这样,如果您提出了更好的解决方案(使用类而不是函数,使用额外的文件来分离思想,等等),那么在您的测试中需要更改的内容就会更少,以适应重构。

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

通常我更喜欢简单导入的自文档风格,只更改from..当我必须输入模块名的次数增加到10到20次时,即使只有一个模块被导入。

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

当你不知道你必须从模块中导入哪个项时,导入模块是最好的。通过这种方式,当问题出现时可能很难进行调试,因为 你不知道哪个项目有问题。 Form module import <foo>是最好的,当你知道你需要导入哪个项目时,它也有助于根据你的需要导入特定的项目。使用这种方式调试可能很容易,因为您知道导入了哪个项。

简单地说,这都是为了方便程序员。在核心级别,它们只是导入模块的所有功能。

import module:当你使用import module时,你必须写module.method()来使用这个模块的方法。每次使用任何方法或属性时,都必须引用模块。

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