1.包导入格式

导入模块时除了使用模块名进行导入,还可以使用目录名进行导入。

例如,在sys.path路径下,有一个dir1/dir2/mod.py模块,那么在任意位置处都可以使用下面这种方式导入这个模块。

import dir1.dir2.mod
from dir1.dir2.mod import XXX

一个实际一点的示例,设置PYTHONPATH环境变量为d:\pypath,然后在此目录下创建以上目录和mod.py文件:

set PYTHONPATH="D:\pypath"
mkdir d:\pypath\dir1\dir2
echo print("mod.py") >d:\pypath\dir1\dir2\mod.py
echo x=3 >>d:\pypath\dir1\dir2\mod.py# 进入交互式python
>>> import dir1.dir2.mod
mod.py
>>> dir1.dir2.mod.x
3

注1:在python3.3版本及更高版本是可以导入成功的,但是在python3.3之前的版本将失败,因为缺少__init__.py文件,稍后会解释该文件
注2:顶级目录dir1必须位于sys.path列出的路径搜索列表下

如果输出dir1和dir2,将会看到它们的是模块对象,且是名称空间。

>>> import dir1.dir2.mod
mod.py>>> dir1
<module 'dir1' (namespace)>>>> dir1.dir2
<module 'dir1.dir2' (namespace)>>>> dir1.dir2.mod
<module 'dir1.dir2.mod' from 'd:\\pypath\\dir1\\dir2\\mod.py'>

这种模块+名称空间的形式就是包(严格地说是包的一种形式),也就是说dir1是包,dir2也是包,这种方式是包的导入形式。包主要用来组织它里面的模块。

从上面的结果也可以看出,包也是模块,所以能使用模块的地方就能使用包。例如下面的代码,可以像导入模块一样直接导入包dir2,包和模块的区别在于它们的组织形式不一样,模块可能位于包内,仅此而已。

import dir1.dir2
from dir1 import dir2

另外,导入dir1.dir2.mod时,它声明的模块变量名为dir1,而不是dir1.dir2.mod,但是导入的对象却包含了3个模块:dir1、dir1.dir2以及dir1.dir2.mod。如下:

>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'dir1']>>> for key in sys.modules:
...     if key.startswith("dir1"):
...             print(key,":",sys.modules[key])
...
dir1 : <module 'dir1' (namespace)>
dir1.dir2 : <module 'dir1.dir2' (namespace)>
dir1.dir2.mod : <module 'dir1.dir2.mod' from 'd:\\pypath\\dir1\\dir2\\mod.py'>

2.__init__.py文件

上面的dir1和dir1.dir2目前是空包,或者说是空模块(再一次强调,包就是模块)。但并不意味着它们对应的模块对象是空的,因为模块是对象,只要是对象就会有属性。例如,dir1包有如下属性:

>>> dir(dir1)
['__doc__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'dir2']

之所以称为空包,是因为它们现在仅提供了包的组织功能,而且它们是目录,而不像py文件一样,是实实在在的可以编写模块代码的地方。换句话说,包现在是目录文件,而不是真正的模块文件。

为了让包"真正的"成为模块,需要在每个包所代表的目录下加入一个__init__.py文件,它表示让这个目录格式的模块(也就是包)像py文件一样可以写模块代码,只不过这些模块代码是写入__init__.py中的。当然,模块文件中允许没有任何内容,所以__init__.py文件也可以是空文件,它仅表示让包成为真正的模块文件。

每次导入包的时候,如果有__init__.py文件,将会自动执行这个文件中的代码,就像模块文件一样,事实上它就是让目录代表的包变成模块的,甚至可以说它就是包所对应的模块文件(见下面示例),所以也可以认为__init__.py是包的初始化文件。在python3.3之前,这个文件必须存在,否则就会报错,因为它不认为目录是有效的模块。

现在,在dir1和dir2下分别创建空文件__init__.py

type nul>d:\pypath\dir1\__init__.py
type nul>d:\pypath\dir1\dir2\__init__.py

现在目录的层次格式如下:

λ tree /f d:\pypath
D:\PYPATH
└─dir1│  __init__.py└─dir2mod.py__init__.py

再去执行导入操作,并输出包dir1和dir2。

>>> import dir1.dir2.mod
mod.py>>> dir1
<module 'dir1' from 'd:\\pypath\\dir1\\__init__.py'>>>> dir1.dir2
<module 'dir1.dir2' from 'd:\\pypath\\dir1\\dir2\\__init__.py'>>>> dir1.dir2.mod
<module 'dir1.dir2.mod' from 'd:\\pypath\\dir1\\dir2\\mod.py'>

从输出结果中不难看出,包dir1和dir1.dir2是模块,且它们的模块文件是各自目录下的__init__.py

实际上,包分为两种:名称空间模块、普通模块。名称空间包是没有__init__.py文件的,普通包是有__init__.py文件的。无论是哪种,它都是模块。

__init__.py写什么内容

既然包是模块,而__init__.py文件是包的模块文件,这个文件中应该写入什么代码?答案是可以写入任何代码,我们只需把它当作一个模块对待就可以。不过,包既然是用来组织模块的,真正的功能性属性应该尽量写入到它所组织的模块文件中(也就是示例中的mod.py)。

但有一项__all__是应该在__init__.py文件中定义的,它是一个列表,用来控制from package import *使用*导入哪些模块文件。这里的*并非像想象中那样会导入包中的所有模块文件,而是只导出__all__列表中指定的模块文件。

例如,在dir1.dir2包下有mod1.py、mod2.py、mod3.py和mod4.py,如果在dir2/__init__.py文件中写入:

__all__ = ["mod1", "mod2", "mod3"]

则执行:

from dir1.dir2 import *

不会导入mod4,而是只导入mod1-mod3。

如果不设置__all__,则from dir1.dir2 import *不会导入该包下的任何模块,但会导入dir1和dir1.dir2。

3.__path__属性

严格地说,只有当某个模块设置了__path__属性时,才算是包,否则只算是模块。这是包的绝对严格定义。

__path__属性是一个路径列表(可迭代对象即可,但通常用列表),和sys.path类似,该列表中定义了该包的初始化模块文件__init__.py的路径。

只要导入的是一个包(无论是名称空间包还是普通包),首先就会设置该属性,默认导入目录时该属性会初始化当前目录,然后去该属性列出的路径下搜索__init__.py文件对包进行初始化。默认情况下由于__init__.py文件后执行,在此文件中可以继续定义或修改__path__属性,使得python会去找其它路径下的__init__.py对模块进行初始化。

以下是默认初始化后的__path__值:

>>> import dir1.dir2
>>> dir1.dir2.__path__
['d:\\pypath\\dir1\\dir2']>>> import dir1.dir3
>>> dir1.dir3
<module 'dir1.dir3' (namespace)>
>>> dir1.dir3.__path__
_NamespacePath(['d:\\pypath\\dir1\\dir3'])

一般来说,几乎不会设置__path__属性。

4.导入示例

import和from导入时有多种语法可用,这两个语句的导入方式和导入普通模块的方式是一样的:import导入时需要使用前缀名称去引用,from导入时是赋值到当前程序的同名全局变量中。如果不了解,请看前一篇文章:python模块导入细节。

假设现在有如下目录结构,且d:\pypath位于sys.path列表中:

$ tree -f d:\pypath
d:\pypath
└── dir1├── __init__.py└── dir2├── __init__.py└── mod.py

只导入包:

import dir1             # 导入包dir1
import dir1.dir2        # 导入包dir1.dir2
from dir1 import dir2   # 导入包dir1.dir2

导入某个模块:

import dir1.dir2.mod
from dir1.dir2 import mod

如果dir2/__init__.py中设置了__all__,则下面的导入语句会导入已设置的模块:

from dir1.dir2 import *

注意,只支持上面这种from...import *语法,不支持import *

导入模块中的属性,比如变量x:

from dir1.dir2.mod import x

5.相对路径导入

注:如果允许,不要使用相对路径导入,很容易出错,特别是对新手而言。使用绝对路径导入,并将包放在sys.path的某个路径下就可以。

假设现在有如下目录结构:

$ tree -f d:\pypath
d:\pypath
└── dir1├── __init__.py├── dir4│   ├── __init__.py│   ├── c2.py│   └── c1.py├── dir3│   ├── __init__.py│   ├── b3.py│   ├── b2.py│   └── b1.py└── dir2├── __init__.py├── a4.py├── a3.py├── a2.py└── a1.py

在dir1.dir2.a1模块文件中想要导入dir1.dir3.b2模块,可以在a1.py中使用下面两种方式导入:

'''
学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import dir1.dir3.b2
from dir1.dir2. import b2

上面的导入方式是使用绝对路径进行导入的,只要使用绝对路径,都是从sys.path开始搜索的。例如,上面是从sys.path下搜索dir1,再依次搜索dir1.dir3.b2。

python还支持包的相对路径的导入,只要使用.或…即可,就像操作系统上的相对路径一样。使用相对路径导入时不会搜索sys.path。

相对路径导入方式只有from…import支持,import语句不支持,且只有使用.或…的才算是相对路径,否则就是绝对路径,就会从sys.path下搜索。

例如,在a1.py中导入dir1.dir3.b2:

from ..dir3 import b2

注意,必须不能直接python a1.py执行这个文件,这样会报错:

    from ..dir3 import b2
ValueError: attempted relative import beyond top-level package

报错原因稍后解释。现在在交互式模式下导入,或者使用python -m dir1.dir2.a1的方式执行。

>>> import dir1.dir2.a1

以下几个示例都如此测试。

在a1.py中导入包dir3:

from .. import dir3

在a1.py中导入dir1.dir2.a2,也就是同目录下的a2.py:

from . import a2

导入模块的属性,如变量x:

from ..dir3.b2 import x
from .a2 import x

相对路径导入陷阱

前面说过一个相对路径导入时的错误:

    from ..dir3 import b2
ValueError: attempted relative import beyond top-level package

dir3明明在dir1下,在路径相对上,dir3确实是a1.py的…/dir3,但执行python a1.py为什么会报错?

from ..dir3 import b2

这是因为文件系统路径并不真的代表包的相对路径,当在dir1/a1.py中使用…dir3,python并不知道包dir1的存在,因为没有将它导入,没有声明为模块变量,同样,也不知道dir2的存在,仅仅只是根据语句直到了dir3的存在。但因为使用了相对路径,不会搜索sys.path,所以它的相对路径边界只在本文件。所以,下面的导入也是错误的:

from . import a2

实际上,更标准的解释是,当py文件作为可执行程序文件执行时,它所在的模块名为__main__,即__name____main__,但它并非一个包,而是一个模块文件,对它来说没有任何相对路径可言。

解决方法是显式导入它们的父包,让python记录它的存在,只有这样才能使用…:

python -m dir1.dir2.a2

还有几个常见的相对路径导入错误:

from .a3 import x

错误:

ModuleNotFoundError: No module named '__main__.a3'; '__main__' is not a package

原因是一样的,py文件作为可执行程序文件执行时,它所在的模块名为__main__,它并非一个包。

最后,建议在条件允许的情况下,使用绝对路径导入,而不是相对路径。

6.使用别名导入

通过包的导入方式也支持别名。例如:

from dir1.dir2.a2 import x as xx
print(xx)import dir1.dir2.a2 as a2
print(a2.x)from dir1.dir2 import a2 as a22
print(a22.x)

python学习:包导入教程相关推荐

  1. 我的世界java材质包转基岩_Minecraft我的世界基岩版材质包导入教程

    Minecraft我的世界基岩版材质包导入教程!大家好这里是千羽,今天为大家带来Minecraft基岩版材质包的导入方法,包括Win10版以及安卓版的材质包导入教程视频,不知道材质包怎么导入的同学可参 ...

  2. python自学平台-Python学习交流平台与教程推荐

    Python学习交流平台与教程推荐 目录 一.有编程问题怎么办? 1 Stack Overflow 2 Github 3 CSDN-专业IT技术社区 二.Python教程 1 跟我读Python文档 ...

  3. Python学习入门基础教程(learning Python)--5.6 Python读文件操作高级

    前文5.2节和5.4节分别就Python下读文件操作做了基础性讲述和提升性介绍,但是仍有些问题,比如在5.4节里涉及到一个多次读文件的问题,实际上我们还没有完全阐述完毕,下面这个图片的问题在哪呢? 问 ...

  4. 2个Python学习网站制作教程

    最近次条总结了一些2个Python学习网站制作教程的一些核心技术,这里整理了下一些目录,分别是两个网站,大部分技术都在前端,熟悉前端的话直接可以查看网页源码对应去了解学习,这些教程重在理解思路,思路通 ...

  5. Python表情包处理教程:如何过滤和替换emoji表情?

    Python表情包处理教程:如何过滤和替换emoji表情? Python是一种高级编程语言,它也是一个非常流行的用于数据分析.机器学习和自然语言处理的工具.在这些领域中使用文字和符号非常重要,但是有时 ...

  6. 25天Maya大神综合学习包「教程 软件 模型库」!月薪5万不是梦

    Maya是美国Autodesk公司出品的世界顶级的三维动画软件,应用对象是专业的影视广告,角色动画,电影特技等.Maya功能完善,工作灵活,易学易用,制作效率极高,渲染真实感极强,是电影级别的高端制作 ...

  7. Python学习之Scrapy教程

    介绍: 这是我的Scrapy教程系列的第一篇文章,在这个Scrapy教程中,我将讨论Scrapy,BeautifulSoup的特性,比较它们,并帮助您决定哪个更适合您的项目. 谈论BeautifulS ...

  8. python跨包导入包_python引入跨模块包

    人生苦短,我学python. 最近学习python,由于包的模块分的比较多.所以要用到跨模块引入 且调用中间的方法 整体目录结构如下. 需求: 在 API模块 user.py 中 调用 plugin ...

  9. Python学习入门基础教程(learning Python)--6.3 Python的list切片高级

    上节"6.2 Python的list访问索引和切片"主要学习了Python下的List的访问技术:索引和切片的基础知识,这节将就List的索引index和切片Slice知识点做进一 ...

  10. python cvxpy包安装教程

    1.直接使用pip安装 pip install cvxpy 有的用户使用该命令可以直接安装,因为他电脑上已经安装了需要安装cvxpy 的依赖包.但是绝大数用户并没有安装全部的依赖,所以需要根据步骤2 ...

最新文章

  1. matepad和鸿蒙,爆料称华为MatePad 2系列平板有三个版本:预装鸿蒙OS
  2. 一个函数两个return
  3. android系统可以破吗,你的手机系统破到什么程度?一键查安卓漏洞
  4. [C++ STL] 各容器简单介绍
  5. (学习笔记)Oracle表空间相关基本命令
  6. Web开发-Django模型层
  7. 【已解决】IDEA:Cannot start compiler:the SDK is not specified for module...
  8. 记录今天登录oracle时遇到的一个小问题--不能登录
  9. Android之如何用cmd方法查看logcat
  10. 在windows下写makefile编译代码
  11. pythontuple数据类型_数据类型-元组Tuple
  12. Java之HSF搭建demo
  13. jaccard相似度_推荐系统中常用计算相似度的方法和工具
  14. mysql 子字符串_Mysql 截取字符串取子集的函数应用
  15. 【论文速读】ChengLin_Liu_ICCV2017_Deep_Direct_Regression_for_Multi-Oriented_Scene_Text_Detection...
  16. 修改系统提供视图类的显示字体
  17. SQL2008数据库可疑状态处理
  18. 前后端分离微服务管理系统项目实战SaaS-HRM项目(七)——POI报表入门
  19. SpringCloud第十章zuul路由网关
  20. Java 创建并应用PPT幻灯片母版

热门文章

  1. matlab ga工具箱 使用教程,MATLAB7.0 GA工具箱详细讲解及实例演示.pdf
  2. Android开发之指南针
  3. 2022年股票估值法研究报告
  4. 判断两个矩形是否相交
  5. 熊出没之奇幻空间里面的机器人图片_《熊出没之奇幻空间》里面令人触动的两个角色...
  6. MAC读取NTFS移动硬盘方法
  7. 通过u盘启动计算机使用ghost安装系统步骤,详细教您如何使用u盘启动盘手动ghost备份系统...
  8. android 输入法下一步,Android Edittext 软键盘输入法回车键改成下一步Next
  9. arcgis图例背景白色,留出空间
  10. 移动互联网周刊第二期,不错,推荐给大家