前言

我看到有些文章说的是:
import 模块:导入一个模块;注:相当于导入的是一个文件夹,是个相对路径。
from…import:导入了一个模块中的一个函数;注:相当于导入的是一个文件夹中的文件,是个绝对路径。

这里说from … import 导入的是一个函数,这种说法是不对的。应该是:
from … import … 可以导入包,模块,函数,类或者变量等等;而import 只能导入包或者模块,不能导入其他

具体说明及差异

拿常见的numpy举例。

部分一

以下是numpy一个子包的内容:

python from用法 路径 python from ..._自定义


在 test_scripts.py 文件中,定义的有几个函数,就拿其中一个 find_f2py_commands() 举例:

python from用法 路径 python from ..._python_02


测试代码:

from numpy.tests.test_scripts import find_f2py_commands
import numpy.tests.test_scripts.find_f2py_commands

if __name__ == '__main__':
    pass
报错信息如下:
ModuleNotFoundError: No module named 'numpy.tests.test_scripts.find_f2py_commands'; 
'numpy.tests.test_scripts' is not a package

也就是说,在 import a.b.c.xxx时,xxx的上一级c需要是一个包才能正确调用。如果c是一个包,就可以得出,最后一级的xxx只能是c的一个子模块,也就说明了前言中的内容:import 只能导入包或者模块

部分二,__init__.py相关

import … 只能从实际路径相对关系导入包或者模块,而from … import … 还可以导入__init__.py中声明的包、模块、函数等等

为了测试,我们在numpy.tests路径下的__init__.py文件中添加:import numpy.random as random,在tests路径中是没有这个包的

python from用法 路径 python from ..._python_03


测试代码:

from numpy.tests import random
import numpy.tests.random

if __name__ == '__main__':
    pass
报错信息如下:
Traceback (most recent call last):
  File "d:\Computer_Programming\python\test\test.py", line 7, in <module>
    import numpy.tests.random
ModuleNotFoundError: No module named 'numpy.tests.random'

两种方法导入之后的使用说明及差异

from a.b import xxx,这种方法在使用时,直接用xxx即可;
import a.b.xxx,就需要使用a.b.xxx

不过,如果这两种方法导入的都是包,则除了上述的名字差异外,使用上都是相同的,都与xxx路径下__init__.py中导入的信息有关

比如,我们在 numpy.tests 路径中添加一个名为 np_test的文件夹(只需要包含一个__init__.py文件即可,内容无所谓有无):

python from用法 路径 python from ..._报错信息_04

然后,测试代码:

import numpy.tests as test_a
# from numpy import tests as test_b
# 可以分别注释掉然后测试,报错信息都相同

if __name__ == '__main__':
    print(test_a.np_test)
    # print(test_b.np_test)
报错信息均为:
AttributeError: module 'numpy.tests' has no attribute 'np_test'

然后修改tests路径下的__init__.py文件,添加:

python from用法 路径 python from ..._python_05


之后再次重复上述测试,就都输出正常了:

python from用法 路径 python from ..._报错信息_06

自定义python包和模块

例如,我们自定义的包为np_test,结构如下:

np_test
--__init__.py
--function.py

__init__.py内容如下:
from . import function

function.py内容如下:
def func_a():
    print('a')

def func_b():
    print('b')

如果自定义的包有一些子包或者子模块,或者想要使用其他已安装的python包(类似上述的random那里)的话,就需要在np_test路径下的__init__.py中进行声明

添加自定义包的存放路径的具体方法见另一篇文章 本文采用的是其中的方法三,将np_test这个自定义包放在了lib\site-packages路径中:

python from用法 路径 python from ..._python from用法 路径_07


之后就是使用的测试代码:

from np_test import function
import np_test

if __name__ == '__main__':
    function.func_a()
    np_test.function.func_b()

输出如下,正确:

python from用法 路径 python from ..._自定义_08


如果__init__.py文件是空文件的话,则以上方法就会报错,原因上文中有说明。

另外,可以修改__init__.py文件的内容,从而更方便的使用np_test包:

将__init__.py内容修改为:
from . import function
from .function import func_a
from .function import func_b

之后测试,就可以直接使用function模块中的函数,而不需要import function相关信息:
import np_test

if __name__ == '__main__':
    np_test.func_a()
    np_test.func_b()
输出正确,同上

附注

如果用的是conda,原理类似