python中import用法,全面详解各种import用法技巧及常见问题解决方法

对于许多刚接触 Python 的开发者来说,Python 中模块的导入机制常常让他们感到困惑。究竟应该使用import xxx?还是使用from xxx import yyy?或者是from xxx.yyy import zzz?又或者是from xxx import *?这些不同的导入方式究竟应该如何选择和使用?

本文将深入探讨这些问题,帮助大家彻底理解 Python 的模块导入机制。

以正则表达式模块为例,我们通常这样编写代码:

但有时,你可能会看到其他人这样写:

这两种导入方式究竟有何不同呢?

我们可以通过type函数来查看它们的类型差异:

如下图所示:

从结果可以看出,使用import re导入的re是一个module对象,即模块。我们称之为正则表达式模块。而使用from re import search时,导入的search是一个function对象,即函数。我们称之为search 函数

一个模块中可以包含多个函数和变量。

如果你在代码中已经明确只需要使用search函数,不再需要正则表达式模块中的其他功能,那么两种导入方式都可以,没有本质区别。

但是,如果你需要使用正则表达式模块中的多个函数或常量,那么第一种方案(直接导入模块)会更加简洁和清晰。

例如:

在这个例子中,你分别使用了re.searchre.subre.Sre.I。其中,后两者是常量,分别用于忽略换行符和忽略大小写。

但是,如果你使用from re import search, sub, S, I来导入,代码将变成这样:

虽然看起来简洁,但在代码行数增多的情况下,你很容易忘记SI这两个变量的具体含义。

此外,如果你自己定义的函数恰好命名为subsearch,就会覆盖正则表达式模块中的同名函数,从而引发难以发现的潜在 bug。

再以 Python 的datetime模块为例,我们可以直接使用import datetime,此时导入的是一个datetime模块,如下图所示:

但如果你使用from datetime import datetime,导入的datetime则是一个type对象,即 Python 中的日期时间类型:

因为这种方式导入的datetime,代表的是 Python 中用于表示日期和时间的类型。

这两种导入方式虽然名称相同,但含义完全不同。请观察以下两种写法:

第二种写法看似简单,但实际上修改起来更为复杂。例如,如果你还需要增加一个变量today来记录当前日期,操作如下:

对于第一种写法,只需增加一行代码即可:

但对于第二种写法,你需要先修改导入部分的代码:

然后才能添加变量:

这样一来,你需要修改两个地方,反而增加了工作负担。

在使用某些第三方库的代码中,我们可能会看到类似这样的写法:

但也可以写成:

然而,下面这种写法会导致错误:

那么这里的lxml.html究竟是什么?

这种情况常见于一些大型第三方库中,这些库能处理多种类型的数据。例如lxml既能处理xml数据,也能处理html数据,因此会划分子模块,lxml.html模块专门负责html相关操作。

现在,我们通过代码示例来演示多种导入方法。

我们创建一个文件夹DocParser,里面分别创建两个文件main.pyutil.py,内容如下:

util.py文件:

main.py文件:

运行效果如下图所示:

现在,我们将main.py的导入方式修改一下:

依然正常运行,如下图所示

当两个文件位于同一个文件夹下,且该文件夹没有__init__.py文件时,两种导入方式等价。

接下来,我们创建一个文件夹microsoft,里面再添加一个文件parse.py

如下图所示:

此时,我们在main.py中调用它:

运行效果如下图所示:

我们也可以使用另一种方法:

运行效果如下图所示:

但是,你不能直接导入microsoft,如下图所示:

你只能导入模块、函数或类,不能直接导入文件夹名称。

无论是使用import xxx还是from xxx.yyy.zzz.www import qqq,你导入的只能是模块(对应于.py 文件的文件名)或某个.py 文件中的函数名、类名、变量名。

无论是import xxx还是from xxx import yyy,你都不能导入一个文件夹的名称。

可能存在一种情况,某个函数名与文件名相同,例如:

microsoft文件夹中有一个microsoft.py文件,该文件中定义了一个名为microsoft的函数,那么你的代码可以写成:

但请注意区分,这里你导入的仍然是模块,只是microsoft.py的文件名与文件夹名相同而已。

无论是使用import还是from import,首要条件是代码能够正常运行。其次,根据代码的维护性和团队的编码风格来选择合适的导入方案。

如果我们只需要使用某个模块中的一个函数(或常量、类),且名称不会产生混淆,可识别性高,那么使用from 模块名 import 函数名是完全可以的。

如果我们需要使用模块中的多个函数,或者函数名、常量名、类名可能产生混淆(例如re.Sre.I),那么使用import 模块名后再通过模块名.xxx调用,会使代码更加清晰,更易于维护。

但无论在什么情况下,都应避免使用from xxx import *这种写法,因为它会带来许多难以预料的麻烦。

原文链接:

https://mp.weixin.qq.com/s/tEN1gLPi5PZVAnt0zbrj2Q