包和模块的概念
当前目录结构为:
1 2 3 4 5
| $ tree . -------- . └── mypackage └── mymodule.py
|
mypackage是一个文件夹,就是一个包。mymodule.py是一个python文件,就是一个模块。所以简单来说,一个包就是一个文件夹,一个模块就是一个.py文件。其中mymodule.py内容为:print('I am mymodule.py')
。
运行python
那么运行方式1:(指定文件路径)
1 2
| $ python3 mypackage/mymodule.py I am mymodule.py
|
运行方式2:(使用-m参数)
1 2
| $ python3 -m mypackage.mymodule I am mymodule.py
|
方式1简单粗暴,指定python文件路径,将其作为可执行文件执行,是执行入口文件。方式2则使用包的概念,执行mypackage这个包里面的mymodule这个模块,依然是将mymodule.py
作为执行入口文件。
补充说明1:使用方式2,需要搜索包和模块, 搜索包和模块的顺序是(查找是否有mypackage的包和mymodule这个模块)
- builtin
a.系统内置包和模块中
- sys.path
a.当前目录下
b.PYTHONPATH这个环境变量目录下
c.Python的安装目录下的site_packages中
1 2 3 4 5 6 7 8 9 10
| $ tree . . └── mypackage └── __main__.py $ cat mypackage/__main__.py print('I am __main__.py')
$ python3 -m mypackage I am __main__.py
|
补充说明2:
若-m后面只有一个参数, 比如 python3 -m xxx
- 优先将xxx理解为包,若该包下有
__main__.py
文件,则理解为 python3 -m xxx.__main__
- 否则将xxx理解为模块,若当前目录下有
xxx.py
, 则理解为 python3 xxx.py
- 以上两种都不是,则报错。
1 2 3 4 5 6 7 8 9
| $ tree . . └── mymodule.py
$ cat mymodule.py print('I am mymodule.py')
$ python3 -m mymodule I am mymodule.py
|
总结:【-m的用法】仅仅是比【直接指定路径用法】多个一个【去系统搜索】的步骤而已,其他无区别。
入口文件和模块文件
上面描述的两种运行方式,mymodule.py
都是入口文件,而其他python文件就是模块文件了。每次运行,只能有一个文件是入口文件。
若一个文件是入口文件,那么这个.py
文件中的__name__
就是 __main__
。
若一个文件不是入口文件,比如被别的.py
文件引用,那么__name__
就是包名.模块名
。
模块文件如何被导入?
既然其他文件就是模块文件了,那么其他模块怎么运行呢? 需要被入口文件导入。导入有三类:
导入包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| $ tree . -------- . ├── mainmodule.py └── mypackage └── mymodule.py -----------------------------------------------------------------------------------------------
$ cat mainmodule.py ------------------- import mypackage -----------------------------------------------------------------------------------------------
$ cat mypackage/mymodule.py --------------------------- print('I am mymodule') -----------------------------------------------------------------------------------------------
$ python3 mainmodule.py -----------------------
|
这样python3 mainmodule.py
就执行成功了, 没有报错,但也没有发生任何事情。
注意:
● mainmodule.py所在的目录非常关键,它代表了顶层包的上一层目录。
● 其实导入包并没有任何意义,因为不会发生任何变化,后续你导入模块依然要填写包名。
● 那么为什么导入包语法没错呢,其实它默认导入的还是模块,叫做init.py模块,这样的话就相当于实现了导入模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| $ tree . -------- . ├── mainmodule.py └── mypackage ├── __init__.py └── mymodule.py ----------------------------------------------------------------------------------------------
$ cat mainmodule.py ------------------- import mypackage ----------------------------------------------------------------------------------------------
$ cat mypackage/__init__.py --------------------------- print('I am __init__.py') ----------------------------------------------------------------------------------------------
$ cat mypackage/mymodule.py --------------------------- print('I am mymodule') ----------------------------------------------------------------------------------------------
$ python3 mainmodule.py ----------------------- I am __init__.py
|
此时你会发现mypackage/init.py中的代码被自动执行了,其实也就是导入init这个模块了。
另外解释一下什么是导入,导入一个模块,就是把该模块中的代码从头到尾执行一遍。
导入一个模块成员,就是声明一下这个模块中的 函数,类,变量等成员,后面可以直接用。比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| $ tree . -------- . ├── mainmodule.py └── mypackage ├── __init__.py └── mymodule.py ----------------------------------------------------------------------------------------------
$ cat mainmodule.py ------------------- import mypackage print('a = ' + str(mypackage.a)) ----------------------------------------------------------------------------------------------
$ cat mypackage/__init__.py --------------------------- print('I am __init__.py') a = 100 ----------------------------------------------------------------------------------------------
$ cat mypackage/mymodule.py --------------------------- print('I am mymodule') ----------------------------------------------------------------------------------------------
$ python3 mainmodule.py ----------------------- I am __init__.py a = 100
|
但是import mypackage 和 import mypackage.init还是有点区别的。区别在于import mypackage是隐式导入init,所以调用的时候,你不能直接使用init这个模块名,也就是直接用mypackage.a而不是mypackage.init.a
当然init.py也可以像其他普通模块一样被显式导入,行为和同普通模块是一样的。
另外 import mypackage的语法,由于没有导入模块,所以你用的所有模块都必须带上mymodule这个前缀。
导入模块
导入模块的语法是import 包名.模块名
。很简单,举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| $ tree . . ├── mainmodule.py └── mypackage ├── __pycache__ │ └── mymodule.cpython-312.pyc └── mymodule.py $ cat mainmodule.py import mypackage.mymodule print('a=' + str(mypackage.mymodule.a))
$ cat mypackage/mymodule.py print('I am mymodule') a = 100
$ python3 mainmodule.py I am mymodule a=100
|
很简单,mainmodule.py
中导入了mypackage.mymodule
,所以可以引用其中的a变量。
不过如果包层级太多,比如mypackage.mymodule
太长了,所以可以一步到位,直接导入模块,比如from mypackage import mymodule
,这样的话,直接用mymodule.a
就可以了,这种语法就是 from 包名 import 模块名
。
1 2
| from mypackage import mymodule print('a=' + str(mymodule.a))
|
这样的话,效果和刚才是一样的。
另外,如果mypackage
目录下有很多模块,可以一下子都导入吗?可以的,用*
代替就可以了。
不过有个前提,就是mypackage
目录下要有个__init__.py
, 且内容定义了__all__ = ['mymodule', 'mymodule2', 'mymodule3']
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| $ tree . . ├── mainmodule.py └── mypackage ├── __init__.py └── mymodule.py
$ cat mainmodule.py from mypackage import * print('a=' + str(mymodule.a))
$ cat mypackage/__init__.py __all__ = ['mymodule']
$ cat mypackage/mymodule.py print('I am mymodule') a = 100
$ python3 mainmodule.py I am mymodule a=100
|
不过 all 不能指定为*,从而导入所有包,也是为了保护不被滥用吧。另外也不能 from mypackage import *
。
导入成员
上面说的是导入包,导入模块,接下来还可以导入成员,这个成员是指模块成员,也就是函数,类,变量等。
注意,成员的导入:from 包名.模块名 import 成员名
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| $ tree . . ├── mainmodule.py └── mypackage └── mymodule.py
$ cat mainmodule.py from mypackage.mymodule import a print('a=' + str(a))
$ cat mypackage/mymodule.py print('I am mymodule') a = 100
$ python3 mainmodule.py I am mymodule a=100
|
导入成员之后,引用的时候就不要加命名空间了(也就是包名.模块名),直接用成员名就可以了。注意可以 from mymoudle import *
, 此时*
默认是所有,若mymodule.py
中有__all__
变量,那么就以__all__
为准。
所以总结一下。
导入包:
1
| a.import mypackage # 等价于 import mypackage.__init__,备注:只要涉及包都会自动隐式导入这个
|
导入模块:
1 2 3
| a.import mypackage.mymodule b.from mypackage import mymodule c.from mypackage import * # 若存在__init__.py且存在__all__变量,则导入__all__所指定;否则 无
|
导入成员
1 2
| a.from mypackage.mymodule import member1, member2,member3 b.from mypackage.mymodule import *
|