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

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


当前回答

我正在回答一个类似的问题,但在我发布之前,发帖者删除了它。这里有一个例子来说明这些区别。

Python库可以有一个或多个文件(模块)。为例子,

package1
  |-- __init__.py

or

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

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

让我们来定义

在mylibrary1下的__init__.py中的Func1 () mylibrary2下的module2.py中的Foo()。

我们可以使用这些方法之一访问func1()

import package1

package1.func1()

or

import package1 as my

my.func1()

or

from package1 import func1

func1()

or

from package1 import *

func1()

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

import package2.module2

package2.module2.foo()

or

import package2.module2 as mod2

mod2.foo()

or

from package2 import module2

module2.foo()

or

from package2 import module2 as mod2

mod2.foo()

or

from package2.module2 import *

foo()

其他回答

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

1. 一般进口:

import math

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

math.sqrt(4)

当然,它增加了输入工作,但作为初学者,它将帮助您跟踪与之相关的模块和函数(一个好的文本编辑器将大大减少输入工作,推荐使用)。

输入工作可以通过使用import语句进一步减少:

import math as m

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

2. 功能导入:

from math import sqrt

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

3.普遍的进口:

from math import * 

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

如果你有一个自己命名为sqrt的函数,并且你导入了math,你的函数是安全的:这是你的sqrt,这是math.sqrt。但是,如果从math import *执行,则会遇到一个问题:即,两个不同的函数具有完全相同的名称。来源:“

有很多答案,但没有一个提到测试(使用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 module import…当我在代码中经常使用一些对象/函数时。

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

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

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

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