当前位置: 首页 > 后端技术 > Python

彻底理解Python中的import

时间:2023-03-26 14:01:19 Python

kingname的第一套乐高大家好,我是谢乾坤,原网易数据挖掘高级工程师。现任微软最有价值专家(Python方向),拥有6年Python开发经验,善于解决各种业务场景中的疑难问题,进一步提升代码质量。对于很多Python初学者来说,Python导入其他模块的方式让他们难以理解。什么时候用importxxx?什么时候使用fromxxximportyyy?什么时候使用fromxxx.yyyimportzzz?什么时候使用fromxxximport*?在本文中,我们将彻底了解这个问题。系统自带的模块以正则表达式模块为例。我们经常会这样写代码:importretarget='abc1234xyz're.search('(d+)',target)但是有时候,你可能会看到有人这样写代码:fromreimportsearchtarget='abc1234xyz'search('(d+)',target)那么这两种导入方式有什么区别呢?我们用type函数看看它们的类型:>>>importre>>>type(re)>>>fromreimportsearch>>>type(search)如图下图中:可以看到,直接使用importre导入re是一个模块类,也就是模块。我们称它为正则表达式模块。而当我们从reimportsearch时,这个search是一个函数类,我们称它为搜索函数。一个模块可以包含多个函数。如果在你的代码中,你已经确定你只使用搜索功能,不会在正则表达式中使用其他功能,那么这两种方法你都可以使用,并没有什么区别。但是,如果你想在正则表达式下使用多个函数,或者一些常量,那么第一种方案会更简洁明了。例如:importrere.search('c(.*?)x',flags=re.S)re.sub('[a-zA-Z0-9]','***',target,flags=re.I)在此示例中,您分别使用了re.search、re.sub、re.S和re.I。后两个是忽略换行符和大小写的常量。但是,如果使用fromreimportsearch,sub,S,I来写代码,那么代码就会变成这样:importresearch('c(.*?)x',flags=S)sub('[a-zA-Z0-9]','***',target,flags=I)看起来很简洁,但是一旦你的代码行多了,你很容易忘记S和I这两个变量是什么。而且,我们定义的函数也有可能被命名为sub或者search,从而覆盖正则表达式模块下的两个同名函数。这会导致许多隐藏的潜在错误。再举个例子。Python的datetime模块,我们可以直接导入datetime,此时我们导入一个datetime模块,如下图:但是如果你写fromdatetimeimportdatetime,那么你导入的datetime是一个类型类:因为这样的importeddatetime是Python中的一种类型,用于表示包括日期和时间在内的数据。这两种导入方式导入的datetime虽然同名,但是含义完全不同。请注意以下两种写法:=1)第二种写法看似简单,其实改起来比较麻烦。比如我还需要添加一个today变量来记录今天的日期。对于第一段代码,我们只需要添加一行:today=datetime.date.today()但是对于第二行,我们需要先修改import部分的代码:fromdatetimeimportdatetime,timedelta,date然后我们可以更改代码:today=date.today()这样,你要修改两个地方,增加了负担。第三方库在使用了一些第三方库的代码中,我们会看到这样的东西:)但是下面的写法会报错:importlxmlselector=lxml.html.fromstring(HTML)那么这里的lxml.html是什么?这种情况在一些特别大的第三方库中比较常见,可以处理多种类型的数据。比如lxml既可以处理xml数据也可以处理html数据,所以这个库会分成子模块,lxml.html模块专门负责html相关的数据。自己实现多种导入方法我们现在自己写代码来实现这几种导入方法。我们创建一个文件夹DocParser,并在其中创建两个文件main.py和util.py。它们的内容如下:util.pyfile:defwrite():print('writefunctioniscalled!')main.pyFile:importutilutil.write()运行效果如下图所示:现在我们修改main.py的导入方式:fromutilimportwritewrite()仍然可以正常使用,如下图?当两个文件在同一个文件夹下,且文件夹内没有__init__.py文件时,两者导入方法是等效的。现在,我们新建一个文件夹microsoft,在里面添加一个文件parse.py:defread():print('我是microsoft文件夹下parse.py中的read函数')如下图:此时我们在main.py中调用:parse.read()运行效果如下图所示:我们还可以使用另一种方法:frommicrosoft.parseimportreadread()运行效果如下图所示:但是,你不能直接导入microsoft,如下图:?只能导入模块或者导入函数、类,不能导入文件夹。无论你使用importxxx还是fromxxx.yyy.zzz.wwwimportqqq,你导入的东西要么是模块(对应.py文件的文件名),要么是函数名、类名、变量名一个.py文件。不管是importxxx还是fromxxximportyyy,你导入的都不能是文件夹的名字。可能会出现这样一种情况,某个函数的名字和文件的名字一样,比如:在microsoft文件夹下有一个microsoft.py文件,在这个文件里有一个叫microsoft的函数,那么你的代码可以这样写:frommicrosoftimportmicrosoft`microsoft.microsoft()但是请注意区分,你这里导入的仍然是一个模块,只是microsoft.py文件的名字和名字完全一致它所在的文件夹。总结无论是使用import还是fromimport,首先要求代码能够正常运行,其次根据代码的可维护性和团队编码风格来决定选择哪种方案。如果我们只在某个模块下使用一个函数(或常量,类),而且名字不混淆,辨识度高,那么frommodulenameimportfunctionname是没有问题的。如果我们将在一个模块下使用多个函数,或者我们将使用的函数名、常量名、类名可能会混淆(比如re.S、re.I),那么在这种情况下,导入模块名,然后调用modulename.xxx将使代码更清晰,更易于维护。但是无论在什么情况下,都禁止使用fromxxximport*这样的写法,它会给你带来无尽的噩梦。更多内容Python开发中有很多陷阱。不仅会严重破坏代码的稳定性,还会影响项目代码开发的效率,影响自己的职业发展,甚至工作状态。其实我们并不想解决问题,也不愿意写所谓“漏洞百出”的代码。就是不知道问题出在哪里,为什么会出现,如何修改。经过多年的业务发展,我详细记录了很多真实的错误和陷阱,并提取了《Python 业务开发常见错误案例集》视频课程42章。错误坑主要分为两类:代码编写和开发思维。点击链接查看视频课详情:https://ke.sifou.com/course/1...课程学习图如下:https://ke.sifou.com/course/1...