一、模块(Module)
- 创建一个
文件夹
或者文件
。
├── run.py
├── calculate
│ ├── add.py
│ ├── divde.py
│ ├── multi.py
│ └── sub.py
调用模块。
# Filename:add.py
def add( a, b):
return a+ b
# Filename:run.py
from calculate import add
print( add.add( 1,2))
调用模块需要用到 from
关键词,如果直接使用 import
会是什么结果?
import calculate.add
print( dir( add))
""" Output
Traceback (most recent call last):
File "./run.py", line 7, in <module>
print( dir( add))
NameError: name 'add' is not defined
"""
add
方法出错了?使用dir()
查看,似乎calculate
包并没有add
方法,这是怎么回事?
没有加 __init__.py 文件!
如果一个包没有__init__.py
文件,就会被看成一个普通的文件夹,虽说普通文件夹也能够import
,但是并不能实现什么功能。
- 添加空
__init__.py
# filename: run.py
import calculate
print( dir( calculate ))
"""
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
"""
为什么还是提示没有 add
方法?明明已经有 __init__.py
文件了?
经查阅资料,
__init__.py
控制着包的导入行为,假如__init__.py
为空,那么仅仅导入包是什么都做不了的,也不能访问包下面的模块;
只有当在__init__.py
将模块逐一import
,导入包后才能有效地使用包中的模块。
当然,没有在__init__.py
中 import 模块的包,还是可以通过 from 包 import 模块的方式导入模块。
所以在 __init__.py
为空的时候,还是可以通过(也只能通过)以下方法使用各个模块。
# filename: run.py
from calculate import add
print( add.add(1,2) )
要注意:包、模块、方法是三个级别的东西,譬如上面的 calculate 是包,import 导入的是 add 模块,模块 add 中的 add 是函数方法。等级一定要清晰明了,不然会出错。
当然,也可以直接导入模块里面的函数方法,这样使用过程中就不用冗长的前缀了。
一般来说,导入包中所有的模块可以使用 from 包 import *,但是看上面一段代码,似乎并没能导入全部模块之后,而单独导入某一个模块是成功的。这是为什么?最终还是要归结于 __init__.py
的内容。
二、包(Package)
- 给
__init__.py
添加内容
将所有的模块名称以列表的形式赋值给__all__属性,就可以导入所有模块。
# filename:__init__.py
# 注意,一定要写包的名称 calculate.作为前缀,不然会找不到模块!
from calculate import (
add,
sub,
multi,
divde
)
__all__ = [ 'add', 'sub', 'multi', 'divde']
# filename: run.py
import calculate
print( dir( calculate ))
"""
['__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'add', 'divde', 'multi', 'sub']
"""
总之,导入时,package 内的 module 是受 __init__.py
限制的。