![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=1738959467-sJNcT2EBKyZoDPVxuN3gqUSEsP7yUyah-0-888308a02a51be9198a886dee5cb98ca)
步骤4:包是可以作为模块来导入的,导入时,__init__.py文件中的代码会被执行(如果__init__.py文件是空白的,则没有代码被执行)。下面代码将包作为模块来导入。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P74_80417.jpg?sign=1738959467-PNmtRn7JKcEOGRwWNd8pVLXB5XvfEx1l-0-f6915d8b4229d333c407ed262d6ab542)
步骤5:还可以从包中导入指定的子模块。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P74_80418.jpg?sign=1738959467-exa6wEei1F2ulYCbE6hZ7uqpkmAQiEXl-0-1cf2f496c12467a0dad3b0f007b227c4)
步骤6:也可以使用from…import语句来导入子模块。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P74_80419.jpg?sign=1738959467-YCSQXvuIqWpt9QOm46n4TO7hm3IezzEg-0-f4ff2622fd2c1478570c037fe7a7d9f9)
步骤7:或者从子模块中导入指定的成员。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P74_80420.jpg?sign=1738959467-X217Z7mVOWIFv5ShdWZkp7aP8trA3dU6-0-1c400ec05006e0f2bc22a7b3395cf9bc)
访问子模块的方式与访问文件类似,写上子模块所在包的名称,每个目录层次之间使用点号(.)分隔。
案例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=1738959467-bEkppcotrEjLWBh6qWeTniwQKFvvKTZI-0-519328497f725c06937d88fdedfe2f90)
步骤3:再在__init__.py文件中定义两个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P75_80423.jpg?sign=1738959467-C6oeWr2mGNuqRVi8vi1xFyTJpxw9eiu8-0-dfdc51dbc00443461d1874a62ebbd3c5)
__name__属性返回test_f1和test_f2函数的名称,并以字符串形式呈现。
步骤4:在需要访问my_pkg包的代码中导入刚刚定义的两个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P75_80424.jpg?sign=1738959467-KlOjwl31tFzxB3AQ93pv4bYNBgcU8UrW-0-df6d7e4b795c586c54d6795617c5b49d)
步骤5:现在可以直接调用这两个函数了。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P75_80425.jpg?sign=1738959467-Oo0mQNPF88V47X9O0dlmv1Ud0Iy8ExaS-0-6cfdb4f4a75eb0ece939b98d6eb5c7ae)
调用后,屏幕上会打印以下文本:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P75_80426.jpg?sign=1738959467-gXMJYGgPgLqNOSzO4sbn9fOjLvNKLy2A-0-8b6899347817ee2894f7fb53cc275587)
案例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=1738959467-S9LsaeNu5SZjQORgBY0L6w2bWeHfftvV-0-9e5d8a7857e342ac821a35e8c9d3a109)
_add函数进行加法运算,_sub函数用于减法运算。
步骤4:再在my_lib目录下新建文件mod2.py,即mod2模块,并在模块中定义两个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P76_80429.jpg?sign=1738959467-5J10fdOaNZzYI1qYuMjXRwiDiPxp4a8V-0-12b1d047b307900a16779c3696d968bb)
_mult函数用于乘法运算,_div函数用于除法运算。
步骤5:回到my_lib目录下的__init__.py文件,依次导入mod1和mod2模块中的成员。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P76_80430.jpg?sign=1738959467-QcjXHrrULkSMs9S2GfVU5V5yFbJbdfLQ-0-4c7f63efa5498965ae2faadac42f4358)
在mod1和mod2模块名称前面加上点号(.),表示相对路径,表示当前包目录下的子模块。如果是两个点,例如..mod,表示当前包目录的上一层目录中的mod模块;要是有三个点,例如...mod,则表示当前包目录的上两层目录下的子模块……以此类推。
步骤6:定义新的变量,分别引用_add,_sub,_mult和_div四个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P76_80431.jpg?sign=1738959467-hldWYhrq5Y1TT7gZBmqYoboNOe9uwi1j-0-f56a29a8e99b83550ef4186e96fee2f7)
mod1和mod2模块中的成员就被合并到__init__.py文件中,并被新的变量引用(相当于分配了别名)。
步骤7:还可以定义__all__属性,为import∗导入方式提供所有公开的成员列表。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P76_80432.jpg?sign=1738959467-rvThexEcKmLdnSJVsvQAOGTpngJcyU7r-0-d00d01b23d7479e881bcb14d8262e339)
步骤8:在需要使用以上模块的代码中,只需要将my_lib包作为模块导入,就可以访问其子模块中的函数了。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P76_80433.jpg?sign=1738959467-e0Yvuepan5bBkSanrxe1hts31CPxEgO4-0-847af5a2bdaf00a98ab4352797a51ad3)
步骤9:尝试访问my_lib中的四个成员。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P77_80435.jpg?sign=1738959467-lDQkfojwq3ve46mu5kAVJinqm0UPt88G-0-8d4c3b72801f59726056eb3ffeade7cf)
案例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=1738959467-KUzCtcRFHwlFmV5aaKtUkHF6KisVaS5l-0-e5e9c924c32646ccc60488638fe6893c)
该案例最终要实现将子模块的成员逐层合并到包(目录)模块的__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=1738959467-8RNKCmvY5D8aD9xHxHYj7oxtr5MNo2G8-0-5ada6de00b3292c0ebd8850bcf5abffd)
步骤3:在project1目录下再新建part_b模块,里面也定义一个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P78_80439.jpg?sign=1738959467-xSr6p0XRAj3A5gtofkBF54rr1efazJ1j-0-3246773b428987066d0668f355d4504c)
步骤4:在project1目录下新建__init__.py文件,将part_a和part_b模块的成员导入,并组成__all__属性。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P78_80440.jpg?sign=1738959467-PYq26KvlVAy7vinhRiAF728lF4ETZiHf-0-fb25f24af064e55ea63f2ecd33700cfa)
__all__属性需要字符串序列,直接访问函数的__name__属性可以获取其名称的字符串表示形式。
接下来完成project2子目录的内容。
步骤5:在root目录下新建project2目录。
步骤6:在project2目录下新建file_checker模块,并在模块中定义一个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P78_80441.jpg?sign=1738959467-8odeLi4ma5GjBDwGYkrXulMGMJzcf3qO-0-59c8fea07a8420033766bd1f59601807)
步骤7:在project2目录下新建__init__.py文件,导入file_checker模块的成员,并放到__all__属性中。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P78_80442.jpg?sign=1738959467-4r1LDJwfVAwSb29kadoBzD7JKa1vKEQg-0-fd155bf5a1d83f36eaf045d03c8c6fda)
步骤8:回到root目录下的__init__.py文件中,分别将project1和project2作为模块导入。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P78_80443.jpg?sign=1738959467-NyJhrcLTNpM8n9Jwiy18SJqVKFkviYkp-0-329bd3559f443fcf909036a1f84cd11c)
步骤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=1738959467-FAHisbDxfyI8M7SUJZsCjPrEiww88bvp-0-5c796176aa23e35a0588196326535a75)
globals函数返回当前模块的名称空间列表(字典格式),然后调用字典的update方法将从project1和project2模块中获得的成员添加到该字典中,这样一来,当前模块中就存在这些成员的引用了,设置__all__属性后不会出错。
步骤10:合并__all__属性的内容。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P79_80447.jpg?sign=1738959467-4tzQP345NbwgKbqxcsJoNWWRVubOBVmC-0-beb2b7048fea244342beff0369536e38)
步骤11:在需要访问root包的代码中,直接导入它的所有成员列表。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P79_80448.jpg?sign=1738959467-BcUWPOupdSlapN4yGw2IGKbu3GvPEStu-0-78a71ee895f56e2f4aa2c3b0964e6767)
步骤12:为了验证一下子模块中的成员是否都合并到root.__all__属性中,可以打印全局的变量名。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P79_80449.jpg?sign=1738959467-vAxtR1wMy03FZxHby9ibhJhbklRuqwZE-0-4d536b50da9b99c76998278247720b39)
打印结果如下:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P79_80450.jpg?sign=1738959467-XG8GsJcClI0GbBvc0g67xYXuFlb1Uvm6-0-8cff037cdc15f2a153e0543984492791)
从结果中看到,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=1738959467-2SxPZtJHryKVwYHXvgkAXUgrQo6xdIii-0-00da4e8b2b52de15713817c194d79322)
执行命令后,会出现下面的提示信息:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P80_80453.jpg?sign=1738959467-nlR7kp80iteQKwTYEg7ztBWWIADC7Z96-0-3f59a13eb0a8548523da400bc5906397)
从提示信息中可以得知:包作为顶层代码被运行时,其目录下面需要__main__模块。在这个模块中可以编写任意可执行的代码,在包被直接运行时,__main__模块中的代码就会执行。
操作流程
步骤1:新建demo目录,即包名称为demo。
步骤2:在demo目录下新建代码文件__init__.py文件,然后在该模块中定义两个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P80_80454.jpg?sign=1738959467-XTqTpOIF0aiVpc9yg07KIp6Mlx0P46t6-0-2811a3f2e2e6bf86a02f32f67be03a2c)
步骤3:在demo目录下新建__main__.py文件,在这个模块中调用刚刚定义的两个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P80_80455.jpg?sign=1738959467-ZoG0uKP11UNMxC8MVDU9FMfcBHH40hUO-0-fdbdf2c1c57985a4596449690be035dd)
步骤4:在命令行终端输入以下命令,将demo包作为顶层代码运行。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P80_80456.jpg?sign=1738959467-9antCEhieB0cjMEJdAF7Xf06s44Mttxn-0-0ce93187aa731a97345d39ecc6446f0c)
此时,__main__.py文件中的代码被执行,输出结果如下:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P81_80458.jpg?sign=1738959467-CcEnIppGM500yG3V05AOtu9EUo6AphyK-0-30d937d74101813988b60c4b43cb9706)
案例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=1738959467-MjhSSR7KlN5pQUnRmAH9WO9RZDpvd8B1-0-605d18e783050d7eb14d32c11e37f877)
步骤3:在my_lib目录下新建代码文件,命名为mod_2.py,对应的模块名为mod_2,然后在模块中也定义一个函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P81_80460.jpg?sign=1738959467-lDIKpzyyMH2GeHj76VRuYYGF8yvaodri-0-eb2efe3ad9dd099b4561d83b43d7a802)
步骤4:在顶层代码模块中,依次导入test_fun_a和test_fun_b函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P81_80461.jpg?sign=1738959467-pB9ckUOUkClvUMtG0zHyoJKMPq8mcrRn-0-2f5e6d5a76a31aadb699d20b98ea26f8)
步骤5:调用导入的函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P81_80462.jpg?sign=1738959467-XLMNW0FZczqBi2BnMaIQL9ykJXcGQXxD-0-c779640d74f33b3cde09b8f5e61ae001)
步骤6:还可以用import语句直接导入my_lib目录。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P82_80464.jpg?sign=1738959467-siBmLnS5NYlNa7ud7EhaccQLLxWWiE1k-0-6879f291a41e59c4bf9c277b3106e8b8)
步骤7:打印my_lib对象的__path__属性。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P82_80465.jpg?sign=1738959467-Zw4X9WCf0qWJSIc5lLcduxxCrZdg4J4y-0-b8a08ace9d64721ec1e98477ef0fd3b2)
得到的输出内容如下:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P82_80466.jpg?sign=1738959467-DvEwydixnPot8c9YMgjpOfQ7x8znT3Ex-0-4e8d19a2d77d95901cc3510a872e5672)
括号中包含的是目录的完整路径。
注意:普通目录可以作为基于名称空间的包使用,但.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=1738959467-y6kok1wP4H8T8HZgV6KIqGvpQ9S3TpQS-0-1aa845b97f5fc48b2fc76a94515497e7)
步骤5:依次打印pack1和pack2的__package__属性的值。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P82_80468.jpg?sign=1738959467-vWoPjBBY4BqpMay48xgf0frLTtUBGiqI-0-95ece5e10239438a3e90c3ac1f2a9473)
输出结果为:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P83_80470.jpg?sign=1738959467-xw11sFQIpXx1bSwXAffMxLsFoyJ97S8i-0-8104d391955568ecbb017b6c4eafb51d)
案例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=1738959467-Hf06b7IR6b6z2oEf2o6V1YMj0tUZTC4C-0-5449fcfcdbbd529a958b14b645c6e7e1)
步骤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=1738959467-kZ6cHBODfxMMnrnmmBeDm62P2wlQ0t6s-0-7d52b35599832fbf4c63effbea98c3c3)
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=1738959467-jOV1ZEJdmvoLRoGLN0hOmL3BUhfNEG98-0-efe1b9d2c0d238cc3bb824ace1a21efa)
步骤7:测试调用test_fun函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P83_80474.jpg?sign=1738959467-zBL7XlhUfR4ZIFRLlADYdLuLWWgkEB1g-0-1c393def675c91756818b4c5452b4dc0)
步骤8:为了验证demo包是否从自定义的路径中导入,可以输出一下包的__path__属性的值。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P84_80476.jpg?sign=1738959467-xMcaEdOnL7cDyfplL7e3GkxJtqtrIX8o-0-273a30d25d7f1d0c47b7343682a55d82)
屏幕上打印的内容为:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P84_80477.jpg?sign=1738959467-IFXBmcvzwh7SY5KRfsgzXa7zARqy4CXD-0-7fd0bc2f03944cec60b7f63c6b29d593)
以上输出表明demo包确实是从自定义的路径下找到的。
案例55 从.zip文件中导入包
导语
Python支持从zip压缩文档中导入包。处理方法与普通目录下的包导入类似,只需将zip文档当作一层目录来处理即可。
假设test包位于sample.zip文件中,那么,test包在导入时会查找以下代码文件:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P84_80478.jpg?sign=1738959467-SEHQQibus1O1z1P0Ov7lG4idngl15Zzu-0-418278bffea367ba9c99f13197a907bc)
但在执行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=1738959467-BhMbEi0u4jAIcxPTX1GK0CSUdpmwp7Di-0-2d37560fe2121dd78468ce44efe22d8a)
步骤3:将demo目录(demo包)放到一个zip压缩文件中,压缩文件命名为myLib.zip。其目录结构如下:
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P84_80480.jpg?sign=1738959467-uxlooMKymG9E32h6OQeQFSqFaSO4s6gD-0-d30d76b7bf671e4474c2bd287f94ece3)
步骤4:在顶层代码中导入sys模块。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P84_80481.jpg?sign=1738959467-GD9vHizFDS2dU7NbgevillbTgPS91Bg4-0-e3e1fde18261d83cdaf749b5406dc73b)
步骤5:将myLib.zip文档的相对路径添加到sys.path列表中。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P85_80483.jpg?sign=1738959467-pv9ohCYDtX3h6OYQYj1KXRKsleQG7y2F-0-439669df39d76358cd8ba64f90db36a8)
步骤6:从demo包中导入func函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P85_80484.jpg?sign=1738959467-m5RlEqtiNFTJOPSg4ziXxxpQOIaCQOJQ-0-a99b76285d7a47eeb679e0110a3461e7)
步骤7:尝试调用func函数。
![](https://epubservercos.yuewen.com/1C5115/23721740309681106/epubprivate/OEBPS/Images/Figure-P85_80485.jpg?sign=1738959467-hWwyKvoKsGMYZ9VD811R88ZdZjGiQIsI-0-889efd22140533f2f4cbd59a7f335860)
步骤8:执行案例代码,如果看到程序输出文本信息“测试程序”,则说明myLib.zip文件中的demo包已被成功导入。
注意:Python程序在执行zip文档中的包时,是不会生成编译文件(.pyc)的。如果希望执行编译后的文件,应当先生成.pyc文件再将其放进压缩文档中。