Python 中包/模块的 `import` 操作
用实例来说明 import
的作用吧。
创建以下包结构。一个文件夹 cookFish/
,下面包含两个文件, __init__.py
和cookBook.py
。
为什么取这几个名字呢?假设我想用 Python 去做和鱼相关的菜,这件事情很复杂,所以我给它创建了一个包,名叫cookFish
, 既然是包,在它下面必须得创建一个文件__init__.py
。烧鱼必备条件之一就是菜谱,所以接着创建了 cookBook.py
。这几个文件对我们这次来说就足够了,所以就没有再创建其他文件了。
cookFish/
__init__.py
cookBook.py
在cookFish/__init__.py
中输入如下代码:
__version__ = '0.1'
__author__ = 'XIE Byron'
def cookFish_hello():
print("cookFish_Hello() from cookFish/__init__.py")
在cookFish/cookBook.py
中输入如下代码:
def cookBook_hello():
print("cookBook_hello() from cookBook.py")
提示:下面的实例都是在 Python 自带的命令行解释器(windows+python 3.7)中运行的结果。如果你在其他环境下运行,比如
jupyter notebook
,输出会有差异。
"import package-name" 都做了什么?
导入包cookFish
。
>>> import cookFish
提示:
如果
import
时出现错误ModuleNotFoundError
,如下:>>> import cookFish
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'cookFish'
建议先将 Python 的当前工作目录设置为
cookFish
的 父文件夹(就是包含cookFish
文件夹的文件夹)。命令如下:>>> import os
>>> os.chdir(r'path\to\parent\folder\of\cookFish')
用dir
操作查看当前命名空间和cookFish
命名空间下都有哪些内容。
>>> dir() # 查看当前命名空间下的对象。注意: cookFish 在当前命名空间下。
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'cookFish', 'os']
>>> dir(cookFish) # 查看 cookFish 命名空间下的对象。
['__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', 'cookFish_hello']
其中的的 __author__
, __version__
, cookFish_hello
是我们定义的,都导入到了 cookFish
的命名空间下。但是cookFish
下的模块 cookBook.py
没有被导入。这是因为直接 import cookFish
只运行cookFish
文件夹下的 __init__.py
文件,不会运行其他模块,所以cookBook
没有被导入。
提示:Python 中的
模块
指后缀.py
的文件,也叫脚本
。包
指包含__init__.py
文件的一个文件夹,一般还会包含其他模块。
包/模块的命名空间
这里讲一下我对概念“在cookFish
的命名空间下”的理解。
Python 的 import A
会把 A
的Python 代码运行一遍,并把运行结果放在一个叫A
的命名空间下。
提示: 如果
A
是包,A
的 Python 代码就是 文件夹A下的__init__.py
中的代码。 如果A
是模块,那么就是文件A.py
中的代码。
import B
会把 B
的 Python 代码运行一遍,并把运行结果放在一个叫 B
的命名空间下。假设A
和B
中都有一个叫X
的对象, A
中的X
在当前命名空间下叫 A.X
,B
中的X
在当前命名空间下叫 B.X
,两个X
在当前命名空间下不重名。
提示: 这里的
对象
指 Python 中的变量/属性,函数,类,实例等等。
比如__version__
属性(或者叫它变量)就在cookFish
的命名空间下,我们只能通过 cookFish.__version__
才能访问到 __version__
,直接输入 __version__
访问不到它,会报错。
直接输入__version__
运行会报如下错误:
>>> __version__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '__version__' is not defined
其他导入包/模块的方式
如果我们想导入 cookFish
下的模块 cookBook
呢?可以用下面的语法:
>>> import cookFish.cookBook
然后在 cookFish
的命名空间下又多了 cookBook
。
>>> dir(cookFish)
['__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', 'cookBook', 'cookFish_hello']
然后就能通过全名cookFish.cookBook
访问cookBook.py
中的对象了,比如:
>>> cookFish.cookBook.cookBook_hello()
cookBook_hello() from cookBook.py
好长的名字啊,能不能短一点啊?当然可以:
>>> import cookFish.cookBook as cb
然后在当前命名空间下就多了对象 cb
:
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'cb', 'cookFish', 'os']
然后就能通过别名cb
来访问cookBook.py
中的对象了,比如:
>>> cb.cookBook_hello()
cookBook_hello() from cookBook.py
那我能不能只导入cookBook_hello()
到当前命名空间?当然可以
>>> from cookFish.cookBook import cookBook_hello
然后 cookBook_hello
就被导入到当前命名空间下了:
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'cb', 'cookBook_hello', 'cookFish', 'os']
然后就能直接访问 cookBook_hello()
了,不用任何前缀:
>>> cookBook_hello()
cookBook_hello() from cookBook.py
“from 包/模块名 import *” 是导入所有对象吗?
那我可以一次性导入 cookFish
下的所有模块、所有包吗?可以也不可以。
Python 有一个条指令
from 包/模块名 import *
比如from cookFish import *
,给我们的第一感觉是,这条指令是遍历了 cookFish
下的所有文件,找到这个包下面的所有包和模块,把他们统统导入到当前命名空间。
但不幸的是,这个操作在windows和Mac系统上不能很好地实现。因为它们的文件系统不能提供准确的文件名大小写信息。在这两个平台上,Python 不知道应该把ECHO.py
导入为模块echo
, Echo
还是ECHO
,或者其他。(比如windows 95 上面,所有文件名的首字母都会显示为大写)。如果Python 把 ECHO.py
导入为 模块Echo
,但实际Python代码中有时按照 echo
使用的,那肯定会报错。[1]
Python 支持大小写,
Echo
和ECHO
是两个不一样的对象
Python 的唯一的解决办法是包的作者提供一个明确的包的索引,告诉 Python 在 Python 代码中如何命名这个模块。import 语句定义下面一个约定,如果在包的 __init__.py
中定义了一个 __all__
列表,在 from xxx import *
时,Python 就会把 __all__
列表中的对象导入。
! 注意:
__all__
只对from xxx import *
有影响,对其他 import 操作没有任何影响
在cookFish/__init__.py
中, 我们只把函数 cookFish_hello
加入__all__
中,代码如下:
__all__ = ['cookFish_hello', ] # added to support `from xxx import *`
__version__ = '0.1'
__author__ = 'XIE Byron'
def cookFish_hello():
print("cookFish_Hello() from cookFish/__init__.py")
重启 Python 解释器,在导入之前,先运行 dir()
显示当前命名空间的对象。
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'os']
! 注意:
Python 解释器为了提高运行效率,同一个模块只会导入一次。一个模块被导入后,再次运行导入命名不会重新导入。为了显示
from xx import *
的特殊性,所以需要重启 Python 解释器(就是关闭 Python 解释器,然后重新进入)。
然后运行如下:
>>> from cookFish import *
然后输入 dir()
查看 cookFish_Hello()
是否被导入到了当前命名空间.
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'cookFish_hello', 'os']
可以看到只有在__all__
列表中的 cookFish_hello
被导入到当前命名空间,其他什么都没有导入,连cookFish
本身也没有被导入。
所以问题“可以一次性导入 cookFish
下的所有模块、所有包吗?“ 的答案是:是否能一次导入,取决于包的作者有没有把所有子模块/子包都加入到 __all__
列表中。
参考
[1] Built-in Package Support in Python 1.5
版本
[1] version 1.0, released on 2019-04-21
[2] version 1.1, released on 2019-04-21
添加了 Python 命令的输出。运行工具为windows版本Python(3.7)自带的命令行解释器。
版权声明:博客为博主原创,允许转载,但必须注明原文地址: https://www.cnblogs.com/byronsh/p/10745292.html
本文的数字签名如下:
MGQCMF13rF3CaChlC2fwTrbc7ajksFng9Cna/V/Eg6rrYVeVeg246Q4E/jLm5crJ5FF5sQIwDu+bzi1fBOof5BSqfx4dsLcBAPTD0R58MbtYXpG9SQiP4AqIhBZjgb6zwK81wX7q
--- 2019-7-20 9:33:43
Python 中包/模块的 `import` 操作的更多相关文章
- 第9.10节 Python中IO模块其他文件操作属性和方法简介
本文中所有案例中的fp都是使用open函数打开文件返回的一个文件对象,为了节省篇幅,大部分没有提供文件打开的代码. 一. 文件是否关闭的属性 属性名:closed 功用:判断文件是否关闭 示例: &g ...
- python中的模块和包
模块 一 什么是模块 模块就是一组功能的集合体,可以通过导入模块来复用模块的功能. 比如我在同一个文件夹定义两个.py文件,分别命名为A.py和B.py,那么可以通过在A文件里通过import B来使 ...
- Python中使用模块和库编程
""" python中使用模块和库编程 导入模块 import modulename [as alias] from modulename import fun1,fun ...
- python中threading模块详解(一)
python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...
- Python中的模块介绍和使用
在Python中有一个概念叫做模块(module),这个和C语言中的头文件以及Java中的包很类似,比如在Python中要调用sqrt函数,必须用import关键字引入math这个模块,下面就来了解一 ...
- python中导入模块的本质, 无法导入手写模块的解决办法
最近身边一些朋友发生在项目当中编写自己模块,导入的时候无法导入的问题. 下面我来分享一下关于python中导入模块的一些基本知识. 1 导入模块时寻找路径 在每一个运行的python程序当中,都维护了 ...
- Python中time模块详解
Python中time模块详解 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. ...
- Python中collections模块
目录 Python中collections模块 Counter defaultdict OrderedDict namedtuple deque ChainMap Python中collections ...
- 正则表达式与Python中re模块的使用
正则表达式与Python中re模块的使用 最近做了点爬虫,正则表达式使用的非常多,用Python做的话会用到re模块. 本文总结一下正则表达式与re模块的基础与使用. 另外,给大家介绍一个在线测试正则 ...
随机推荐
- softmax in pytorch
背景 在分类中,最常见的设置是一个输入,输出是类数目大小的向量.预测的输入类将是在最后一个网络层中具有最大条目的相应类.在分类任务中,交叉熵损失(交叉熵)是训练这类网络最常见的损失函数.交叉熵损失可以 ...
- Burp Suite Pro 教程
1.Burp Suite Pro2.0.11破解版-2018.11.06更新 说明基地址 来源:http://ximcx.cn/post-110.html 启动;如果是用的burp2.0,把下面的代码 ...
- Python练手例子(11)
61.打印出杨辉三角形. #python3.7 from sys import stdout if __name__ == '__main__': a = [] for i in range(10): ...
- CUDA执行模型
1.设备管理和查看: cudaError_t cudaGetDeviceProperties(cudaDeviceProp * prop,int device) 用户可以通过这个函数来查看自己GPU设 ...
- javaScript Event Loop + NodeJs问题解析
http://www.ruanyifeng.com/blog/2014/10/event-loop.html https://github.com/ElemeFE/node-interview/tre ...
- java小练习
打印99乘法表 因为有9行9列,所有要用两个for循环 int m; for (int i = 1; i < 10; i++) { for (int j = 1; j <= i; j++) ...
- .NET Core 微服务架构 Steeltoe 使用(基于 Spring Cloud)
阅读目录: 1. Spring Cloud Eureka 注册服务及调用 2. Spring Cloud Hystrix 断路器 3. Spring Cloud Hystrix 指标监控 4. Spr ...
- Java二叉树实现及递归与非递归遍历实现
树的遍历分两种:1.深度优先遍历 1.1 递归算法实现 2.2 非递归算法实现(使用栈存储)2.广度优先遍历(使用队列存储) import java.util.*; /** * 类功能描述: 二叉树遍 ...
- Java面试大纲-java面试该做哪些准备,java开发达到这样的水平可以涨工资
Java培训结束,面临的就是毕业找工作.在找工作时,就要针对性地做充分的面试准备.准备不充分的面试,完全是浪费时间,更是对自己的不负责. 上海尚学堂Java培训整理出Java面试大纲,其中大部分都是面 ...
- CS20SI-tensorflow for research笔记: Lecture1
本文整理自知乎专栏深度炼丹,转载请征求原作者同意. 本文的全部代码都在原作者GitHub仓库github CS20SI是Stanford大学开设的基于Tensorflow的深度学习研究课程. 什么是T ...