用实例来说明 import 的作用吧。

创建以下包结构。一个文件夹 cookFish/,下面包含两个文件, __init__.pycookBook.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 的命名空间下。假设AB中都有一个叫X的对象, A 中的X在当前命名空间下叫 A.XB中的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 支持大小写,EchoECHO是两个不一样的对象

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` 操作的更多相关文章

  1. 第9.10节 Python中IO模块其他文件操作属性和方法简介

    本文中所有案例中的fp都是使用open函数打开文件返回的一个文件对象,为了节省篇幅,大部分没有提供文件打开的代码. 一. 文件是否关闭的属性 属性名:closed 功用:判断文件是否关闭 示例: &g ...

  2. python中的模块和包

    模块 一 什么是模块 模块就是一组功能的集合体,可以通过导入模块来复用模块的功能. 比如我在同一个文件夹定义两个.py文件,分别命名为A.py和B.py,那么可以通过在A文件里通过import B来使 ...

  3. Python中使用模块和库编程

    """ python中使用模块和库编程 导入模块 import modulename [as alias] from modulename import fun1,fun ...

  4. python中threading模块详解(一)

    python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...

  5. Python中的模块介绍和使用

    在Python中有一个概念叫做模块(module),这个和C语言中的头文件以及Java中的包很类似,比如在Python中要调用sqrt函数,必须用import关键字引入math这个模块,下面就来了解一 ...

  6. python中导入模块的本质, 无法导入手写模块的解决办法

    最近身边一些朋友发生在项目当中编写自己模块,导入的时候无法导入的问题. 下面我来分享一下关于python中导入模块的一些基本知识. 1 导入模块时寻找路径 在每一个运行的python程序当中,都维护了 ...

  7. Python中time模块详解

    Python中time模块详解 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. ...

  8. Python中collections模块

    目录 Python中collections模块 Counter defaultdict OrderedDict namedtuple deque ChainMap Python中collections ...

  9. 正则表达式与Python中re模块的使用

    正则表达式与Python中re模块的使用 最近做了点爬虫,正则表达式使用的非常多,用Python做的话会用到re模块. 本文总结一下正则表达式与re模块的基础与使用. 另外,给大家介绍一个在线测试正则 ...

随机推荐

  1. BFC特性下多栏自适应布局

    BFC 已经是一个耳听熟闻的词语了,网上有许多关于 BFC 的文章,介绍了如何触发 BFC 以及 BFC 的一些用处(如清浮动,防止 margin 重叠等).虽然我知道如何利用 BFC 解决这些问题, ...

  2. 勾勾街——一个专注于免越狱免签名的苹果ios APP打包生成的网站

    自涛舅舅研发的“苹果ios APP自助生成系统”上线以来,每天都有大量的用户注册和生成免越狱app,为什么? 因为我们有明显的技术优势,APP不需要上架appstore, 生成APP又不需要企业签名证 ...

  3. php魔术方法__get(),__set(),__isset()的使用

    1.魔术方法__get(),__set(),__isset()类: <?php /** * @purpose: 魔术方法 __get() , __set(), __isset() 的使用 * U ...

  4. Linux shell编程 -test

    test 命令的格式非常简单 test condition condition 是test命令要测试的一系列参数和值.当用在if-then 语句中时,test 命令看起来是这样的 if test co ...

  5. Linux 结构化命令

    if -then 语句 if -then 语句有如下格式 if command then commands f i bash shell 的if语句会先运行if后面的那个命令,如果改命令的退出状态码是 ...

  6. Centos7 编译测试工具 wrk bombardier iftop

    1.wrk 安装及使用----------------------------------------------------------------------------------------- ...

  7. layui layer弹框中表格的显示

    场景描述:点击iframe里面的一个按钮,需要在父级弹出一个弹框表格. 问题描述:这个弹框的分页不能正常显示,如果把layer.open前面的parent去掉,就可以正常显示. 代码展示: paren ...

  8. python编程从入门到实战1-3章

    print('hellow world') """ 多行注释"""#大小写print('i love you')mssage='hellow ...

  9. 5 个免费的受欢迎的 SQLite 管理工具【申明:来源于网络】

    5 个免费的受欢迎的 SQLite 管理工具 包含内容: SQLite Expert – Personal Edition SQLite Expert 提供两个版本,分别是个人版和专业版.其中个人版是 ...

  10. 微服务架构-选择Spring Cloud,放弃Dubbo

    Spring Cloud 在国内中小型公司能用起来吗?从 2016 年初一直到现在,我们在这条路上已经走了一年多. 在使用 Spring Cloud 之前,我们对微服务实践是没有太多的体会和经验的.从 ...