为什么Python这么好用?毫无疑问,大量现成好用的内置/第三方库是必不可少的。那么我们如何使用它们呢?哦对了~用到了importxxx这个语句。这个问题的起因是我之前在使用PyCharm开发的时候(又)踩了一个坑……废话不多说,说一个像下面这样的工程结构:Projetc_example|--A|--alpha。py|--beta.py|--B|--theta.py|--main|--假设main.py在main.py中导入theta.py:#main/main.pyfromBimportthetawill很明显导致了我们不想要的问题,就是Python不知道去哪里找这个名为B的模块(package是一个特殊的模块):Traceback(mostrecentcalllast):File"main/main.py",line1,infromBimportthetaModuleNotFoundError:Nomodulenamed'B'但是这很奇怪,为什么在PyCharm中运行相同的代码?import的搜索路径于是我们苦苦思索,上下搜索。原来在Python中,import语句其实封装了一系列的过程。查找是否导入了同名模块首先,Python会根据importxxx指定的包名查找sys.modules,查看当前环境中是否已经存在对应的包——不要奇怪为什么会有sys.modules。模块而不导入sys模块。sys是Python的内置模块,也就是自己的儿子。导入只是一个意思,让我们这样的外行也可以在导入的环境中使用相关接口。其实对应的数据自始至终对Python都是透明的。.我们可以importsys查看这个对象的具体内容(节省篇幅,做省略处理):>>>importsys>>>sys.modules{'sys':,'builtins':,...'re':,...}这些是Python一开始就加载的模块,也就是Python安装好后,运行环境一准备好就准备好的模块——但是作为外行,我们是不能直接使用的,我们要向Python报告它们做好准备:“嘿,我要用你儿子了~”很容易发现sys.path中列出的加载模块之间存在明显的差异。模块都有yyy'的字样,这个yyy好像是一条路径。这和我们接下来要讲的步骤有关。在特定路径下找到对应的模块。前面我们提到过,当我们导入一个模块时,Python会先查询sys.modules,看看是否有同名的模块。当然,如果我们找到它,每个人都会很高兴。Python直接为我们使用这个模块。那也罢了,毕竟儿子那么多,借出去挣点外快不是好事吗?但问题是:找不到怎么办?这显然是一个非常现实的问题。毕竟资源是有限的,Python也不可能一个脑子把你可能用到的模块都装完,不然这样,男加男加男加男……没人受得了,不行(大雾,所以会有人给你)Python想出了一个主意:然后你等到需要用到它的时候,再去找他说他是你的儿子。凡是消费的人,你都可以做我的儿子。”就这样,一些本来就不是蟒蛇之子的人,因为各种原因聚集在了这些餐厅里,准备暂时被称为蟒蛇之子的佣兵。这比周文王一开始收100个养子优雅多了,养家压力也没那么大了(Python:什么?我自己的儿子都100多个?你在说什么?听不见你——回到正经画风——其实在Python中,sys.path维护着这样一个py事务的结果(咦?莫名其妙好像发现了什么),里面保存的内容就是这些“指定的”restaurants",也就是当Python遇到不认识的子模块时,会去外地找路径。我们也可以打印出来看具体内容:>>>sys.path['','E:\\Anaconda\\Anaconda\\python37.zip','E:\\Anaconda\\Anaconda\\DLLs','E:\\Anaconda\\Anaconda\\lib','E:\\Anaconda\\Anaconda','E:\\Anaconda\\Anaconda\\lib\\site-packages','E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32','E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32\\lib','E:\\Anaconda\\Anaconda\\lib\\site-packages\\Pythonwin']是基因rally安装环境时配置的一些包的路径,其中一个元素代表当前执行脚本所在的路径。也正是因为如此,我们才可以自由调用同目录下的其他模块。3、将模块与名称绑定,找到对应的非出生模块。加载包后,我们必须为其指定一个指定的名称,这样我们才能在脚本中使用这个模块。当然,大部分时候我们是感知不到这个过程的,因为我们只是一个import去世界各地转:importsysimportosimport此时请求我们指定的模块,其实也是指定的对象名,会用于后面调用相应的模块。换个更明显的:importrequestsasreq如果此时只使用第二种方法导入requests模块,显然在后续程序中,我们不能使用requests的名字来调用它但应该使用req.这就是Python导入过程中的namebinding,本质上和普通赋值没有太大区别。加载一个对象后,给对象赋一个指定的变量名。当然,即使是已经加载的模块,我们也可以使用这种名称绑定机制为其取别名,例如:>>>importsys>>>importsysassy>>>sys.path['','E:\\Anaconda\\Anaconda\\python37.zip','E:\\Anaconda\\Anaconda\\DLLs','E:\\Anaconda\\Anaconda\\lib','E:\\Anaconda\\Anaconda','E:\\Anaconda\\Anaconda\\lib\\site-packages','E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32','E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32\\lib','E:\\Anaconda\\Anaconda\\lib\\site-packages\\Pythonwin']>>>sy.path['','E:\\Anaconda\\Anaconda\\python37.zip','E:\\Anaconda\\Anaconda\\DLLs','E:\\Anaconda\\Anaconda\\lib','E:\\Anaconda\\Anaconda','E:\\Anaconda\\Anaconda\\lib\\site-packages','E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32','E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32\\lib','E:\\Anaconda\\Anaconda\\lib\\site-packages\\Pythonwin']>>>sys==syTrue问题已解决。以上就是对Python导入机制的大致介绍,但是说了半天,我们的问题还是没有解决:如何在项目中简洁的跨模块导入其他模块?使用PyCharm时,一切顺利,因为PyCharm会自动将项目的根目录添加到导入的搜索路径,也就是像下面这样的工程结构,自然可以在任意模块中通过importA导入模块A,通过importBProjetc_example|--A|--alpha.py|--beta导入模块B.py|--B|--theta.py|--main|--main.py但是在非IDE环境中呢?或者在本机Python环境中?很自然地,我们会想到:那就手动把项目根目录添加到sys.path中。说起来和PyCharm做的一样。没关系。你很精明。不如跟我学学修仙?所以我们会使用sys和os这两个模块来做。简介,不多说了)-咚咚咚咚-太棒了#Peoject_example/A/alpha.pyprint("name:"+__name__)print("file:"+__file__)defal():print("Importingalphasucceeded.")在main.py中添加一个逻辑,将项目根目录添加到sys.path中:importosimportsyssys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))importA.alphaA.alpha.al()#name:A.alpha#file:*\Project_example\A\alpha.py#导入alpha成功。大功告成,风口紧~本文小结Python的导入机制介绍来源于一个容易找的问题。事实上,限于篇幅,导入机制只是一个概述,具体内容更加复杂。本文提到的三个步骤适用于比较常见的情况,了解这三个步骤足以应对很多问题。以上就是本次分享的全部内容。想了解更多python知识,请前往公众号:Python编程学习圈,发“J”免费领取,每日干货分享