Python 中包/模块的 `import` 操作
Python 中包/模块的 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")
"import package-name" 都做了什么?
导入包cookFish。
import cookFish
提示:
如果import时出现错误ModuleNotFoundError,如下:
ModuleNotFoundError Traceback (most recent call last)
in
----> 1 import cookFish
ModuleNotFoundError: No module named 'cookFish'
建议先将 Python 的当前工作目录设置为 cookFish 的 父文件夹(就是包含cookFish文件夹的文件夹)。命令如下:
import os
os.chdir(r'pathtoparentfolderofcookFish')
用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__ 运行会报如下错误:
NameError Traceback (most recent call last)
in
----> 1 verison
NameError: name '__verison__' is not defined
其他导入包/模块的方式
如果我们想导入 cookFish 下的模块 cookBook呢?可以用下面的语法:
import cookFish.cookBook
然后就能通过全名cookFish.cookBook访问cookBook.py中的对象了,比如:
cookFish.cookBook.cookBook_hello()
好长的名字啊,能不能短一点啊?当然可以
import cookFish.cookBook as cb
然后就能通过别名cb来访问cookBook.py中的对象了,比如:
cb.cookBook_hello()
那我能不能只导入cookBook_hello()到当前命名空间?当然可以
from cookFish.cookBook import cookBook_hello
然后就能直接访问 cookBook_hello()了,不用任何前缀:
cookBook_hello()
“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 解释器,运行如下:
from cookFish import *
! 注意:
Python 解释器为了提高运行效率,同一个模块只会导入一次。一个模块被导入后,再次运行导入命名不会重新导入。所以需要重启 Python 解释器(就是关闭 Python 解释器,然后重新进入)。
然后输入 dir() 查看 cookFish_Hello()是否被导入到了当前命名空间.
dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'cookFish_hello', 'os']
可以看到只有在__all__列表中的 cookFish_hello被导入到当前命名空间。
所以问题“可以一次性导入 cookFish 下的所有模块、所有包吗?“ 的答案是:是否能一次导入,取决于包的作者有没有把所有子模块/子包都加入到 __all__列表中。
参考
[1] Built-in Package Support in Python 1.5
版本
[1] version 1.0, released on 2019-04-21
版权声明:博客为作者原创,允许转载,但必须注明原文地址: https://www.cnblogs.com/byronxie/p/10745292.html
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
百度面试两板斧:手写算法问基础
阅读本文大概需要 4 分钟。 17年7月份,我参加了百度的实习生面试,随后在百度开始了半年的实习生活,18年7月份,我参加了百度的校招提前批面试,由于可以同时参加百度多个部门的提前批面试,结果我前前后后面试了10多次,也算是一段比较奇葩的经历了。 当然,实习生面试是这里面最简单的一次了,三轮面试,前两轮都是在问基础,问的也不深入,第三轮面试则直接谈人生谈理想。其实百度的日常实习生面试难度确实比校招要来的容易,因为百度一年四季都在招实习生,反观阿里和腾讯,只有在春招期间招收实习生。 既然上面的面试难度不太具有代表性,那么我还是来说说秋招的百度面试经历吧。 大家都知道,阿里内部用Java居多,腾讯内部用C++居多,而百度内部的语言则是五花八门,Java、C++、Python、PHP,都有一定数量的人在用,所以百度的面试题也会比较杂,什么都有可能考,但亦不会考的特别难。 手写算法是百度秋招必考的一个环节,我那时候都是电话面试,所以直接是用在线写代码的网站来做题的(面试官可以实时看到你的代码情况)手写算法一般是压轴环节,也就是面试官问完基础题,就会开始让你写算法题。 题目的难度也不尽相同,有的...
- 下一篇
使用 Jaeger 完成服务间的链路追踪
世上本没有路,走的人多了,便变成了路 -- 鲁迅 本次讨论的话题就是需要在各个服务之间踏出条"路",让 bug 有"路"可循。 至于为什么用 jaeger... 这个支持多语言方案算么?遵循 opentracing 规范算么?开箱即用算么?还有更多? 至于为什么遵循 opentracing 规范的好... 这个...杠精同学,文末地址可参考 反正先撸袖开干... 了解 Jaeger 使用之前先了解: Jaeger: open source, end-to-end distributed tracingJaeger: 开源的、分布式系统的端到端追踪Monitor and troubleshoot transactions in complex distributed systems在复杂的分布式系统之间做监控及问题排查的事务处理。 jaeger 体系和流程如下图 jaeger-client (OpenTracing API 各语言的实现,用于在应用中塞入信息采集点) jaeger-agent (负责发送的进程,对 spans 进行处理并发送给 collector,监听 spans 的 U...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- MySQL8.0.19开启GTID主从同步CentOS8
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装