![Python实战指南:手把手教你掌握300个精彩案例](https://wfqqreader-1252317822.image.myqcloud.com/cover/214/44510214/b_44510214.jpg)
2.2 包
案例47 让普通目录变成包
导语
包(Package)实际上是一个目录(就好比模块实际上是一个代码文件一样)。当某个目录下存在一个名为__init__.py的代码文件时,Python就会将该目录视为包。
包的作用是对模块进行分类。包与模块的关系,如同目录与文件的关系,如果代码模块数量较多,而且都放到根目录(根目录一般是相对的路径)下,会显得混乱,既不利于管理,也不利于识别。通过包对模块进行分类存放,会使应用程序的功能划分更加细化,结构更加清晰。
操作流程
步骤1:新建目录,命名为packages。
步骤2:在packages目录下新建代码文件,命名为__init__.py。__init__.py文件中无须编写任何代码,只要目录下存在此文件,该目录就会被识别为包。
步骤3:在packages目录下新建代码文件,命名为demo.py(模块名为demo),作为packages包的子模块。然后在demo模块中定义show函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P74_80416.jpg?sign=1738871795-HhbxcWgjV2DoxMdAk7GQsK1sTmIDAgyM-0-d63a46098888dbc318f684c68f8f1d77)
步骤4:包是可以作为模块来导入的,导入时,__init__.py文件中的代码会被执行(如果__init__.py文件是空白的,则没有代码被执行)。下面代码将包作为模块来导入。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P74_80417.jpg?sign=1738871795-Rxq56j6ur1WhKuwvEmvVbuA3w79Gr50C-0-289008da30d8b655310993925750b30d)
步骤5:还可以从包中导入指定的子模块。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P74_80418.jpg?sign=1738871795-EB2zUhmXUnrSFYCZPYaOOWdr2HQg35GO-0-5e6ca4b8eb1befcd635ff6c1ef8099c2)
步骤6:也可以使用from…import语句来导入子模块。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P74_80419.jpg?sign=1738871795-sQxVPCQYsseYH02rrAnkCUZzWXh3Escn-0-7ae9aacb417c0b4f4abb26dab0768158)
步骤7:或者从子模块中导入指定的成员。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P74_80420.jpg?sign=1738871795-Cy01wMzMLcDK93jGRHTwmjf8rVjmw4Lw-0-c07bcfca05c2b4b49cf2033f97ebafa8)
访问子模块的方式与访问文件类似,写上子模块所在包的名称,每个目录层次之间使用点号(.)分隔。
案例48 __init__.py文件
导语
目录中包含__init__.py文件时,Python就会将该目录视为包,而且__init__.py文件可以留空白。当包初始化时会执行__init__.py文件(例如当包被导入时)。
__init__.py虽然有特殊用途,但其本质也是代码文件,因此该文件中可以放置任意可执行的代码,也可以定义变量、函数、类等对象。当包作为模块导入时,还可以通过__init__.py文件来合并子模块中的成员(即把子模块的成员导入__init__.py文件中)。
操作流程
步骤1:新建目录,命名为my_pkg,然后在目录下新建代码文件__init__.py,使my_pkg目录成为包目录。
步骤2:在__init__.py文件中调用print函数,输出字符串。当my_pkg包初始化时会执行此代码。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P74_80421.jpg?sign=1738871795-ixA4ssyvYblNewtNCLu330EQH7lejFjv-0-ff122bfe4083fd0bf10ea5f7efefdaf6)
步骤3:再在__init__.py文件中定义两个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P75_80423.jpg?sign=1738871795-KFojhCoz2jUPJW5f7tyKUDhoZNewVSf4-0-d6efccbf985435ab72e4f05cf8cb3527)
__name__属性返回test_f1和test_f2函数的名称,并以字符串形式呈现。
步骤4:在需要访问my_pkg包的代码中导入刚刚定义的两个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P75_80424.jpg?sign=1738871795-NOSssPlTStCblYJcatJKGZSqr26KtJRf-0-7606eeadea30266b89b788827869fa81)
步骤5:现在可以直接调用这两个函数了。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P75_80425.jpg?sign=1738871795-lHK0kvJxoctsnnR46xdNCWQrlqkLp4BE-0-39c407a4baa7f5dca331199690d3709b)
调用后,屏幕上会打印以下文本:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P75_80426.jpg?sign=1738871795-0lzefvnqzYI1xPcyLKuTOsAuL1q1FvfZ-0-aec9228901e5f568b4a15dca39ead9d6)
案例49 合并子模块的成员列表
导语
由于包是一个目录,因此它下面既可以包含代码模块(子模块),也可以包含子目录(子包),子包下还可以包含代码模块,就类似于常见的文件夹与文件的关系。
如果编写的代码结构很复杂(目录层次很多),其他人在调用时会感觉到吃力,还需花时间和精力去弄清楚代码结构(有时候即便撰写了帮助文档也无法将代码结构描述清楚),而且有些代码可能是为了实现某些功能而编写的,只用于内部实现,代码的调用者是不需要关注的。
为了解决上述问题,让代码调用者能够很方便地访问相关的成员对象,可以在包下面的__init__.py文件中将子模块的成员进行合并,统一公开。__init__.py文件本质上也是代码模块,所以可以在该文件中定义新的变量来引用子模块的成员,也可以使用__all__变量。
操作流程
步骤1:新建目录my_lib。
步骤2:在my_lib目录下新建__init__.py文件,使该目录成为包目录。
步骤3:在my_lib目录下新建mod1.py文件,模块名为mod1。并在mod1模块中定义两个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P76_80428.jpg?sign=1738871795-G4U22rYcdFzbX4SUcT1MtWVToYyqNMq5-0-b1e8fde11860e18d9d7a87c3c7f5b554)
_add函数进行加法运算,_sub函数用于减法运算。
步骤4:再在my_lib目录下新建文件mod2.py,即mod2模块,并在模块中定义两个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P76_80429.jpg?sign=1738871795-FT0bPy1eFVjbB9y4nIOBSOSWsq64KGak-0-57b8c9de373dab42fedc7f3f274e5fe3)
_mult函数用于乘法运算,_div函数用于除法运算。
步骤5:回到my_lib目录下的__init__.py文件,依次导入mod1和mod2模块中的成员。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P76_80430.jpg?sign=1738871795-YJoYVDJF2GoH8bjcqjnTFkjzDxskDxep-0-5fd7828a56833c73f68b18193d22c3c1)
在mod1和mod2模块名称前面加上点号(.),表示相对路径,表示当前包目录下的子模块。如果是两个点,例如..mod,表示当前包目录的上一层目录中的mod模块;要是有三个点,例如...mod,则表示当前包目录的上两层目录下的子模块……以此类推。
步骤6:定义新的变量,分别引用_add,_sub,_mult和_div四个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P76_80431.jpg?sign=1738871795-3fe9BTwbrhNq57TK3LFde530xAOKgTh1-0-0488ddea18efad58777a63718bb3ac65)
mod1和mod2模块中的成员就被合并到__init__.py文件中,并被新的变量引用(相当于分配了别名)。
步骤7:还可以定义__all__属性,为import∗导入方式提供所有公开的成员列表。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P76_80432.jpg?sign=1738871795-DA0msfXsklaUhJbzPy40CxCPFiki2CoR-0-d0eeeba78f75e15beec966d4ed1a5c2a)
步骤8:在需要使用以上模块的代码中,只需要将my_lib包作为模块导入,就可以访问其子模块中的函数了。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P76_80433.jpg?sign=1738871795-vY5ELJaCfX9GSh8t9etE0fKljDYSIPsN-0-36ba165c631f5ab39dd26edb8884f200)
步骤9:尝试访问my_lib中的四个成员。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P77_80435.jpg?sign=1738871795-4nkvH5LvjKm3OXFXmILVmitIsDGtDB0f-0-d69e6b47fc81435cfd81015968942360)
案例50 合并多个__init__.py文件中的__all__属性
导语
将其他__init__.py文件中的__all__属性内容合并到当前__init__.py文件的__all__属性中,这种情况多用于把包的子目录中的__all__属性合并根目录中,以方便其他代码访问(使用from…import∗语句就可以从包的根目录导入各级子目录下的所有成员)。
本案例中,包的根目录名为root,root目录下面有两个子目录——project1和project2。project1目录下有part_a、part_b两个模块;project2目录下有file_checker模块。整体结构如下:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P77_80436.jpg?sign=1738871795-zh0IvunXnxdyZPfHgrh6UXzvDndOJioh-0-8b62ce71c2b73d3e06bb58822da3c6b2)
该案例最终要实现将子模块的成员逐层合并到包(目录)模块的__all__属性中。即将part_a模块中的list_all函数和part_b模块中的set_task_id函数合并到project1.__init__模块的__all__属性中;将file_checker模块中的is_same函数合并到project2.__init__模块的__all__属性中;最后再把project1.__init__.__all__和project2.__init__.__all__两个属性的内容合并到root.__init__.__all__属性中。
操作流程
步骤1:新建root目录,作为包的根目录,然后在root目录下建立__init__.py文件(先保留空白,后面步骤中会添加代码)。
步骤2:在root目录下新建project1目录,再在project1目录下新建模块part_a,里面定义一个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P77_80437.jpg?sign=1738871795-SAkcEarhAfqMJwpc7EbCb8FbBIE33IdE-0-969b99ba1c16164f3bea7c960d55f0c3)
步骤3:在project1目录下再新建part_b模块,里面也定义一个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P78_80439.jpg?sign=1738871795-NrgqGagKec1jOgDtJHqq7TYcgFXsLJSs-0-864a8cc80370fb9d06e469d9945a00c9)
步骤4:在project1目录下新建__init__.py文件,将part_a和part_b模块的成员导入,并组成__all__属性。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P78_80440.jpg?sign=1738871795-W8sYSh6PjNqVcZUQ95kBSChecfgJAnzX-0-e901703e9aa85d556ae5b4ad70325936)
__all__属性需要字符串序列,直接访问函数的__name__属性可以获取其名称的字符串表示形式。
接下来完成project2子目录的内容。
步骤5:在root目录下新建project2目录。
步骤6:在project2目录下新建file_checker模块,并在模块中定义一个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P78_80441.jpg?sign=1738871795-VSgI5NH0UZBoj56ohLwE8ATJ6a30OvBP-0-5992fd8e8f198bb42245f814cd21ff7e)
步骤7:在project2目录下新建__init__.py文件,导入file_checker模块的成员,并放到__all__属性中。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P78_80442.jpg?sign=1738871795-7eaN07UEQEavrcpbu1rwqXdQhH7F9HOw-0-fe5654f2144552a5cc3b9ac1c52fe1dd)
步骤8:回到root目录下的__init__.py文件中,分别将project1和project2作为模块导入。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P78_80443.jpg?sign=1738871795-wlyOkiKOQ1d04Yo6svVgdTiV5f8TjkHa-0-6ae2a4e16404280d4ff72917c7a1629f)
步骤9:在设置__all__属性的值之前,需要完成一个重要操作。由于root.__init__模块中并没有导入root.project1和root.project2目录中的模块,因此root模块的名称空间中是不存在list_all、set_task_id和is_same这些函数的记录的,如果直接设置__all__属性,在运行时会出错(名称空间中找不到这些成员)。所以,在设置__all__属性前,要把project1和project2中由__all__属性列出的成员复制到当前名称空间中,代码如下:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P78_80444.jpg?sign=1738871795-2mDjTvzm2vS8myDsMQyx3JtAqRP1rYAX-0-ef63c853abc7d3485d258017b70c413d)
globals函数返回当前模块的名称空间列表(字典格式),然后调用字典的update方法将从project1和project2模块中获得的成员添加到该字典中,这样一来,当前模块中就存在这些成员的引用了,设置__all__属性后不会出错。
步骤10:合并__all__属性的内容。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P79_80447.jpg?sign=1738871795-V4x5MfJuXzysEfYmGxAbEhLQWmOgkFDN-0-63bd5277e0ba3213067ab2bc4d21a05f)
步骤11:在需要访问root包的代码中,直接导入它的所有成员列表。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P79_80448.jpg?sign=1738871795-w2uOu3MjUJQSYD4AbT72T8b33uUjjisw-0-575d20cf9cc35f35e44ebddb75a433ac)
步骤12:为了验证一下子模块中的成员是否都合并到root.__all__属性中,可以打印全局的变量名。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P79_80449.jpg?sign=1738871795-fHAnCrPKfAMNyV2WMb9vNlTHMdSwTKh4-0-f08428cc782beb08d38dbb4c26997f0f)
打印结果如下:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P79_80450.jpg?sign=1738871795-zEErbKFct7aAf2VH0mX3t4RSW8nHDKVd-0-511e5ac16d5f763156837d3906344c03)
从结果中看到,list_all、set_task_id、is_same这三个函数的名字已经在当前模块的名称空间中了,表明它们已被成功合并。
案例51 __main__.py文件的用途
导语
作为包的目录下有时会存在一个名为__main__.py的文件,当包作为模块被直接运行时(作为顶层代码运行,而非被其他模块导入),就会执行__main__.py文件中的代码。这种情况类似于当模块文件被作为顶层代码运行时,模块的__name__属性会变成__main__。
假设有一个名为test的包,可通过以下python命令运行:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P80_80452.jpg?sign=1738871795-SyS3nWEkJKYwCaoZa7NewzTH2Jg3VZbC-0-a1aaf2bc6b44ed95e976edc78bdcec3a)
执行命令后,会出现下面的提示信息:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P80_80453.jpg?sign=1738871795-EP67pjAp9kSYFFrbe8djwH3qoYbli7tL-0-7db5140972e9592103f570b4ff1ba8ac)
从提示信息中可以得知:包作为顶层代码被运行时,其目录下面需要__main__模块。在这个模块中可以编写任意可执行的代码,在包被直接运行时,__main__模块中的代码就会执行。
操作流程
步骤1:新建demo目录,即包名称为demo。
步骤2:在demo目录下新建代码文件__init__.py文件,然后在该模块中定义两个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P80_80454.jpg?sign=1738871795-XvWo4N2QzHY99pK3pxqxHJgtPhlZYVi7-0-a7afa495829336dc0cafffb6b1d1bf93)
步骤3:在demo目录下新建__main__.py文件,在这个模块中调用刚刚定义的两个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P80_80455.jpg?sign=1738871795-eqnPWZHIFdsLsW9v5A7ZtOHuRWkvyKD4-0-681d217d8b99c00872c9051de08d9721)
步骤4:在命令行终端输入以下命令,将demo包作为顶层代码运行。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P80_80456.jpg?sign=1738871795-BZJYPsaa4sYN9gkK7CvH9kwtXo47yo7A-0-06e4a24ccefae9dbcbf6ad69dcda0876)
此时,__main__.py文件中的代码被执行,输出结果如下:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P81_80458.jpg?sign=1738871795-1xumek9ypRwdS9ulSZCiHCWTZaHbEUBC-0-5a329fe28e41f49b33d1dbd6971eb7c9)
案例52 基于名称空间的包
导语
如果包作为模块被导入,此模块对象会存在一个__path__属性。对于规范的包(目录下面包含__init__.py文件)而言,__path__属性是列表类型(list),其中包含包目录的路径。不过,如果某个目录下没有__init__.py文件,尽管不会被识别为正常的包,但是该目录仍然可以在代码中进行导入,这种将普通目录导入为模块的包称为“基于名称空间的包”(Namespace Package)。
基于名称空间的包目录被导入后,它的__path__属性并非常规的列表类型,而是名为_NamespacePath的内部类型(完整路径为_frozen_importlib_external._NamespacePath)。
由于基于命名空间的包没有__init__.py文件,不能编写初始化代码,所以一般不会直接导入目录,而是导入目录中的代码模块(.py文件)。导入之后,对模块成员的访问方式与正常的包一样。
操作流程
步骤1:新建目录,将其命名为my_lib,用于存放模块文件。
步骤2:在my_lib目录下新建代码文件,命名为mod_1.py,即模块名为mod_1,并在模块中定义一个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P81_80459.jpg?sign=1738871795-BRaWya2TU1HGYpQWmDs5OO4bu2jhNIW8-0-6df413c2c4813f8d7c7b84c114838633)
步骤3:在my_lib目录下新建代码文件,命名为mod_2.py,对应的模块名为mod_2,然后在模块中也定义一个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P81_80460.jpg?sign=1738871795-RF2gANBvGY920JXa68xwGi7BNqv3sv7F-0-950c92354f69aedaee544cd1050b8c51)
步骤4:在顶层代码模块中,依次导入test_fun_a和test_fun_b函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P81_80461.jpg?sign=1738871795-dGy5IbCrdWbf2j3tXsIA0YaXJrSBQJOL-0-f43e5d7faf974d393291ac9b454ae59b)
步骤5:调用导入的函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P81_80462.jpg?sign=1738871795-0IQycG1mYPAaogKboijzXE7iUgcqVyXE-0-172e6ce3b6a0e0cae938a7ad3a58d3ae)
步骤6:还可以用import语句直接导入my_lib目录。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P82_80464.jpg?sign=1738871795-dxNS15WV3tV5027zg50EN770QofTYhSE-0-7b8c2ceb08defd7c575bb8ee3fc6977b)
步骤7:打印my_lib对象的__path__属性。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P82_80465.jpg?sign=1738871795-rARiRLJS2BonlqfJJdKx5ViwE6iovAxQ-0-1884ad7a918c81da4c879fd3b0df05b9)
得到的输出内容如下:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P82_80466.jpg?sign=1738871795-KRuUeQacy1b8HztDIwcngGrjtC45H8s0-0-32d39cd67b61d0c5185e076a66c6e638)
括号中包含的是目录的完整路径。
注意:普通目录可以作为基于名称空间的包使用,但.zip文件中的普通目录是不能作为基于名称空间的包使用的。也就是说,.zip文件中的目录如果要作为包使用,目录中就必须存在__init__.py文件。
案例53 __package__属性
导语
如果导入的模块是包(Package),那么它的__package__属性表示此包的路径(路径用点号分隔),多数情况下,__package__属性的值与__name__属性相同;如果导入的模块不是包,那么__package__属性的值是一个空字符串。
操作流程
步骤1:新建目录lib_root。
步骤2:在lib_root目录下新建pack1目录,再在pack1目录下新建__init__.py文件,表明pack1目录是包(__init__.py是个空文件)。
步骤3:在lib_root目录下新建pack2目录,再在pack2目录下新建__init__.py文件,使pack2目录成为包(__init__.py也是空文件)。
步骤4:在顶层代码模块中分别导入pack1和pack2两个包。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P82_80467.jpg?sign=1738871795-KRid1LCseQS23RviHalQNDoMpJGhGoOJ-0-5eaa7c030b2647297bf9422c140cf36d)
步骤5:依次打印pack1和pack2的__package__属性的值。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P82_80468.jpg?sign=1738871795-M3fPxUsDAHmp7jpk07Ij4bXbpki6QzUK-0-a26ea704cffed92ada9915edfcc493cf)
输出结果为:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P83_80470.jpg?sign=1738871795-AdJv63cDzxSudPVeX5cHkh0Oy26hMkVB-0-bcb2947b9353eb86f92915ff4cee337a)
案例54 自定义包或模块的搜索路径
导语
Python应用程序在运行时,会在sys模块的path属性所提供的路径列表中查找被导入的包(或模块)。由于path属性是列表类型(list类),因此可以在运行时通过代码进行修改。
通常不建议删除path列表中元素,因为Python程序在初始化的过程中会向path列表添加一些必要的路径(这些路径包含Python标准库的路径),如果将这些路径删除,有可能导致Python代码无法正常执行。所以,推荐的做法是向path列表中添加需要的路径。
操作流程
步骤1:新建目录,命名为demo。
步骤2:在demo目录下新建__init__.py文件,使demo目录成为包目录。
步骤3:在__init__模块中定义一个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P83_80471.jpg?sign=1738871795-u9bOnx67H4VgaUWdkyByvuWnlqZjOBJo-0-d0e423a5cee0458c2508bee5bab8073e)
步骤4:将demo目录移动到当前示例以外的路径中。例如,本案例将demo目录移动到Windows操作系统下的C:\cust_libs目录下。
步骤5:在顶层代码模块中,在sys.path列表添加自定义的查找路径,本案例中为C:\cust_libs。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P83_80472.jpg?sign=1738871795-MUZXlVinxDSgzFW8Dg36RqqN7hwJgIdx-0-9cbec8e65c8ab35922d65c9e3b6efdc0)
insert方法将自定义的路径添加到path列表的顶部。路径C:\cust_libs加上了r前缀,表示此字符串中的字符不进行转义(即原义字符),如果不使用r前缀,那么路径中的“\”字符必须进行转义(即“\\”)。
步骤6:从demo包中导入test_fun函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P83_80473.jpg?sign=1738871795-swwrFPoY8mC42uRHujAOhTOrP6zGxHC3-0-a726de1f399eab65ddf3e7b8722d6e0f)
步骤7:测试调用test_fun函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P83_80474.jpg?sign=1738871795-d0hSYQFlZNdaYL2wBlgiRcQrAZmY4Hiv-0-0e3e94aa5d287bdd960fa3ea1839b204)
步骤8:为了验证demo包是否从自定义的路径中导入,可以输出一下包的__path__属性的值。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P84_80476.jpg?sign=1738871795-7GxQ1s2klXtsMZs1Y2eKlTocZ9ChPAeQ-0-20ffdd57863fba3c7cfcae7a79037463)
屏幕上打印的内容为:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P84_80477.jpg?sign=1738871795-h8rLoAujslYz1RdmVYqvhNu582EUBD4r-0-680fd0426f7d24c71e1ebd8a0d7566ef)
以上输出表明demo包确实是从自定义的路径下找到的。
案例55 从.zip文件中导入包
导语
Python支持从zip压缩文档中导入包。处理方法与普通目录下的包导入类似,只需将zip文档当作一层目录来处理即可。
假设test包位于sample.zip文件中,那么,test包在导入时会查找以下代码文件:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P84_80478.jpg?sign=1738871795-uvrx6ptXuK7xlUx2M88ewlAk0rZUAuz2-0-cadd9dffc215f1421933a9d6326c757b)
但在执行import语句前,要将zip文档所在的路径添加到sys.path列表中,以便应用程序能够搜索压缩包中的内容。
操作流程
步骤1:新建demo目录,并在目录下新建__init__.py文件。
步骤2:在__init__.py文件中定义一个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P84_80479.jpg?sign=1738871795-fKpRWeGQpDk6BP22Rftlt37AcSaL0Vh4-0-76e0113f97a09c075aca58fbc54a8d44)
步骤3:将demo目录(demo包)放到一个zip压缩文件中,压缩文件命名为myLib.zip。其目录结构如下:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P84_80480.jpg?sign=1738871795-zuzbgSLHo2AOAdVYcGUYlVVLl8pBzFgo-0-02f6de0f61cd7e93d07b1d769ddb680c)
步骤4:在顶层代码中导入sys模块。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P84_80481.jpg?sign=1738871795-1NZy23U4fLiidVl4cR6kBVAR8plmRV4C-0-418be1c0d91dfccb9b523f9fbb9a25b2)
步骤5:将myLib.zip文档的相对路径添加到sys.path列表中。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P85_80483.jpg?sign=1738871795-5BS0ZhKwiBjr6LQvl4PEKWc372TY5Nka-0-3e85cb441391bc1c6de92fbb51ecb745)
步骤6:从demo包中导入func函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P85_80484.jpg?sign=1738871795-u6l9IBJlMZlS6iLUBt5qixJiUpWo0PqC-0-fa5ac51b9185a99bd18dda2b59e7cc41)
步骤7:尝试调用func函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P85_80485.jpg?sign=1738871795-FExFBs7twhkdVcIRktF5tlI3M3LNxAIc-0-b925f4495f1ffe089fbc9756be093ab1)
步骤8:执行案例代码,如果看到程序输出文本信息“测试程序”,则说明myLib.zip文件中的demo包已被成功导入。
注意:Python程序在执行zip文档中的包时,是不会生成编译文件(.pyc)的。如果希望执行编译后的文件,应当先生成.pyc文件再将其放进压缩文档中。