python 是通过module组织代码的,每一个module就是一个python文件,但是modules是通过package来组织的。

如果我们自己写着玩,有的时候就是一两个Python文件在同级目录下,但是当我们开始尝试开发更为复杂的项目的时候,package这个概念的使用就有助于我们组织我们写的一个个modules。

module的概念相对简单,所以不会再多说,主要是说一下package。

Python package

package的定义很简单,在当面目录下有__init__.py文件的目录即为一个package。

但是这会分为两种情况,第一种情况是一个空的__init__.py文件,另外一个情况是写了代码的__init__.py文件。不管是空的还是有内容的,这个目录都会被认为是一个package,这是一个标识。

package的初始化工作

一个package 被导入,不管在什么时候__init__.py的代码都只会被执行一次

>>> import package

hello world

>>> import package

>>> import package

由于 package 被导入时 __init__.py 中的可执行代码会被执行,所以小心在 package 中放置你的代码,尽可能消除它们产生的副作用,比如把代码尽可能的进行封装成函数或类。

__init__.py内的导入顺序

当我尝试导入

from package import something

import语句会首先检查something是不是__init__.py的变量,然后检查是不是subpackage,再检查是不是module,最后抛出ImportError

所以检查顺序如下:

__init__.py 文件内变量

是不是package内的subpackage

是不是package内的module

看个例子

我们有一个如下结构的package

在a.py文件内有一个函数

def bar():

print("Hello, function 'bar' from module 'a' calling")

在b.py文件内有一个函数

def foo():

print("Hello, function 'foo' from module 'b' calling")

然后我们添加一个空的__init__.py 文件在simple_package里面。

我们看下,当我们import simple_package的时候到底会发生什么事情(在simple_package内激活Python shell 或者simple_package的的路径被包含在python的sys.path或者在PYTHONPATH的环境变量中)

>>> import simple_package

>>>

>>> simple_package

>>>

>>> simple_package.a

Traceback (most recent call last):

File "", line 1, in

NameError: name 'a' is not defined

>>>

>>> simple_package.b

Traceback (most recent call last):

File "", line 1, in

NameError: name 'b' is not defined

我们可以看到simple_package已经被成功导入,但是a.py和b.py并没有被导入

当然了,如果你希望使用import simple_package后自动加载a或者b 模块,这里有两种办法。

第一种就是在__init__.py内导入a或者b模块,然后保存再激活python的交互环境

#__init__.py

import a

import b

当你再次尝试import simple_package后,就可以使用simple_package.a.bar()来使用模块a中的bar()函数了。

第二办法就是手动导入,当你想使用模块a中的bar()函数时,需要手动导入

import simple_package.a as a

然后就是可以a.bar()来使用bar()函数了。

一个更复杂的例子

这是一个来自官方的例子

文件结构如下

sound

|-- effects

| |-- echo.py

| |-- __init__.py

| |-- reverse.py

| `-- surround.py

|-- filters

| |-- equalizer.py

| |-- __init__.py

| |-- karaoke.py

| `-- vocoder.py

|-- formats

| |-- aiffread.py

| |-- aiffwrite.py

| |-- auread.py

| |-- auwrite.py

| |-- __init__.py

| |-- wavread.py

| `-- wavwrite.py

`-- __init__.py

你可以将这个package的例子下载下来。如果直接使用import sound来导入这个package,我们可以导入package sound,但是sound的子package(effects,filters,formats)并不会被自动导入。子package不会被自动导入的原因是因为在sound目录下的__init__.py文件并没有任何关于导入子package的代码。

我们来看下在sound目录下的__init__.py的代码

"""An empty sound package

This is the sound package, providing hardly anything!"""

print("sound package is getting imported!")

然后我们导入sound试下

>>> import sound

sound package is getting imported!

>>> sound

>>> sound.effects

Traceback (most recent call last):

File "", line 1, in

AttributeError: module 'sound' has no attribute 'effects'

如果你想使用子package的内容,但是在父package的__init__.py的文件内并没有导入,你需要手动导入

>>> import sound.effects

effects package is getting imported!

>>> sound.effects

如果你希望python帮你自动导入sound.effects你可以往sound目录下的__init__.py文件写入

"""An empty sound package

This is the sound package, providing hardly anything!"""

import sound.effects

print("sound package is getting imported!")

那么你下次运行的时候python就会自动帮你导入sound.effects

>>> import sound

effects package is getting imported!

sound package is getting imported!

当然了,除了使用绝对路径你可以使用相对路径来导入sound.effects

"""An empty sound package

This is the sound package, providing hardly anything!"""

from . import effects

print("sound package is getting imported!")

这跟linux的命令行比较像,.代表当前目录,..代表上级目录

所以你可以在sound.effects的__init__.py文件内写入

from .. import formats

来导入sound.formats。

当你使用sound的时候就会发现,sound.effects和sound.formats都被导入了

>>> import sound

formats package is getting imported!

effects package is getting imported!

sound package is getting imported!

最后我想给你展示下,怎么从sound.effects导入sound.filters.karaoke模块,将一下代码加入到sound.effects的__init__.py文件中

"""An empty effects package

This is the effects package, providing hardly anything!"""

from .. import formats

from ..filters import karaoke

print("effects package is getting imported!")

激活python的交互环境以后,尝试import sound

>>> import sound

formats package is getting imported!

filters package is getting imported!

Module karaoke.py has been loaded!

effects package is getting imported!

sound package is getting imported!

现在我们可以使用karaoke的函数了

>>> sound.filters.karaoke.func1()

Funktion func1 has been called!

>>>

把你的整个package都导入进来

还是用前面的例子,这一次,我会额外的加入一个叫做foobar的模块在主目录,你可以在这里下载例子

我们尝试使用*来进行全部的导入

>>> from sound import *

sound package is getting imported!

我们可以看到仅仅是导入了sound这个package但是其他的内容并没有导入。

>>> dir()

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

__all__

我们可以使用__all__这个魔法变量来手动导入模块和子package,当你定义了__all__到__init__.py文件以后,python会根据你在list内给出的元素进行逐个导入

__all__ = ["formats", "filters", "effects", "foobar"]

所以我们可以再次导入试试

>>> from sound import *

sound package is getting imported!

formats package is getting imported!

filters package is getting imported!

effects package is getting imported!

The module foobar is getting imported

看下dir()

>>> dir()

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'effects', 'filters', 'foobar', 'formats']

>>>

你会发现所有模块都已经被顺利导入。

那如果我们仅仅导入sound.effectspackage内所有内容呢,会发生什么,我们import的时候到底import的是什么。

我们看下结果

>>> from sound.effects import *

sound package is getting imported!

effects package is getting imported!

>>> dir()

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

>>>

你会发现他仅仅是导入了sound.effects这个package,跟你没有修改sound的__init__.py之前是类似情况,仅仅是导入了这个package。

所以你也可以修改sound.effects的__init__.py文件来导入effects内的所有模块

__all__ = ["echo", "surround", "reverse"]

看下结果

>>> from sound.effects import *

sound package is getting imported!

effects package is getting imported!

Module echo.py has been loaded!

Module surround.py has been loaded!

Module reverse.py has been loaded!

>>>

>>> dir()

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'echo', 'reverse', 'surround']

>>>

总结

在 from package import * 语句中,如果 __init__.py 中定义了 __all__ 魔法变量,那么在__all__内的所有元素都会被作为模块自动被导入(ImportError任然会出现,如果自动导入的模块不存在的话)。

如果 __init__.py 中没有 __all__ 变量,导出将按照以下规则执行:

此 package 被导入,并且执行 __init__.py 中可被执行的代码

__init__.py 中定义的 variable 被导入

__init__.py 中被显式导入的 module 被导入

reference

对于python来说、一个模块就是一个文件-彻底明白Python package和模块相关推荐

  1. python打开一个不存在的文件报错,python中的文件操作(一)

    文件就是把一些数据存储存放起来,可以让程序下一次执行的时候直接使用,而不必重新制作一份,省时省力. python操作文件的步骤 1.将文件抽象成一个python的对象 2.对这个对象,进行读/写的动作 ...

  2. python用os.system打开wav文件_使用python读取wav格式文件

    ** 使用python读取wav格式文件 ** - 基本概念 [采样频率] 即取样频率, 指每秒钟取得声音样本的次数.采样频率越高,声音的质量也就越好,声音的还原也就越真实,但同时它占的资源比较多.由 ...

  3. python的ide环境中创建文件_使用Python开发环境Wing IDE设立项目注意事项

    使用Wing IDE的第一步是建立一个项目文件,这样Wing IDE就可以找到并分析源代码,存储工作. Wing IDE会自动以默认的项目进行启动.在本教程中用户也可以使用这个默认项目进行示例操作.如 ...

  4. python创建一个新的txt文件-如何在python中编辑文本文件并创建一个新的文本文件?...

    我有这样的文本文件:>ENST00000511961.1|ENSG00000013561.13|OTTHUMG00000129660.5|OTTHUMT00000370661.3|RNF14-0 ...

  5. python下载网页中的pdf文件_【Python】Python的urllib模块、urllib2模块批量进行网页下载文件...

    由于需要从某个网页上下载一些PDF文件,但是需要下载的PDF文件有几百个,所以不可能用人工点击来下载.正好Python有相关的模块,所以写了个程序来进行PDF文件的下载,顺便熟悉了Python的url ...

  6. python能不能用c打开文件_C/C++/Python等 使用二进制模式打开文件与不使用二进制模式的区别...

    C语言中文本文件与二进制文件的区别 一.文本文件与二进制文件的定义 大家都知道计算机的存储在物理上是二进制的,所以文本文件与二进制文件的区别并不是物理上的,而是逻辑上的.这两者只是在编码层次上有差异. ...

  7. python脚本下载钉钉的文件_利用python下载钉钉群直播视频

    今年因为疫情的原因不能开学,所以很多学校都使用钉钉进行在线授课,但是在钉钉里面点击下载群直播回放的时候却发现: 真好,管理员设置了不允许下载回放. 这就完了吗?NoNoNo!既然正常途径下载不了,那么 ...

  8. dede问答模块 那个php文件相对重要,DEDE问答(ask)模块游客匿名提问和解答

    先说一下实现后的效果,首先这个修改后是一个精简版的dedecms问答系统,会取消采纳答案等功能,因取消会员功能后不再有答案的等级之分,如对答案的平分功能等将被取消. 最后不建议使用匿名提问功能,建议使 ...

  9. python写自动化运行脚本_bat文件一键运行python自动化脚本

    ThinkPHP3.2.3 安装教程 本文以  Windows  平台为例 安装前准备:Windows操作系统的电脑,php编程环境(配置好了Apache.MySql.php).推荐wampserve ...

最新文章

  1. C 一个数组删除一项 并且移位
  2. Java split(“\\s+“) 和 split(“+“) 有什么区别
  3. 几种常用的排序算法之JavaScript实现
  4. Fiori 花瓣动画效果的实现原理
  5. 转载:div和flash层级关系问题
  6. Android之TabLayout和ViewPager组合跳转到指定页面
  7. eigen冲突 sophus 安装_SLAM-Sophus模板库安装总结
  8. 图的深度优先搜索遍历
  9. 《智能优化算法及其MATLAB实现》书籍出版啦
  10. Atitit 计算机系统结构 计算机系统结构 Cpu 存储 cache 指令系统 目录 Line 56: 第2章指令系统设计 指令格式 寻址方式 1 Line 64: 第3章CPU及其实现
  11. java 反编译 报错_java反编译后再编译成class时提示缺少包
  12. jsp基础教程清华版源代码
  13. 在VB中使用API“SHFileOperation”删除文件的三个问题
  14. 教你怎么录制电脑内部发出的声音
  15. 解决安装office2007的各种工具时提示“安装程序找不到office.zh-cn/*”的问题
  16. raw格式镜像文件转vmdk
  17. Error Code: 1054. Unknown column 'xxx' in 'field list'
  18. java将小写金额转为大写金额
  19. PERMISSION_UNFINISHED
  20. Golang如何正确的停止Ticker

热门文章

  1. My first syscall
  2. 使用JavaScript选择GridView行的方法汇总
  3. python3+django写的个人笔记博客
  4. PHP NULL 合并运算符
  5. HTTP Status 404 - No result defined for action com.csdhsm.struts.action.LoginAction and result error
  6. HTML5 MediaStream的运用
  7. 袁新生《LINGO和Excel在数学建模中的应用》
  8. WebForm实现增删改查
  9. C风格字符串和C++ string 对象赋值操作的性能比较
  10. 程序猿必备的10款web前端开发插件一