微信公众号:码农充电站pro
我的主页:https://codeshellme.github.iohtml
正确的判断来源于经验,然而经验来源于错误的判断。
—— Fred Brooksjava
目录python
咱们已经知道函数
是一种重复利用代码的机制。git
本节咱们来介绍模块
,Python 中的模块,也是一种重复利用代码的机制。咱们能够将有特定功能
的代码(好比函数
,类
等)写在模块中,供他人使用,便于重复利用,便于维护。github
在前面的章节中,咱们也接触过模块。Python 功能强大的一个重要的缘由,就是它有各类方便使用的模块。shell
Python 中的模块能够分为两种:编程
import
就可以使用import
咱们写的Python 代码都是以.py
为后缀,Python 模块也是以.py
为后缀,其实每一个Python 代码文件,均可以看作是一个Python 模块。微信
咱们编写以下代码:数据结构
#! /usr/bin/env python3 # 定义一个字符串 PY = 'Hi Python.' # 定义一个函数 def hello_py(): print('Hello Python.')
将该代码写在一个名为hello.py
的文件中,该文件就是一个hello
模块,将该文件放在~/hi
目录中。app
注意:
在定义模块时,要避免与已有的模块起相同的名字,会引发冲突
咱们进入~/hi
目录,打开python3
交互式环境。
dir()
函数
在引入模块以前,咱们先使用dir()
函数,来查看当前环境可用的函数/变量
:
>>> dir() ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
能够看到,除了几个魔法方法
外,没有任何其余可用的函数/变量
。
咱们定义一个变量s
:
>>> s = 'abc'
再用dir()
函数查看,能够看到多了一个s
变量:
>>> dir() ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 's']
import
模块
在使用模块时,须要先引入模块。引入模块,须要使用import
关键字。
咱们输入以下代码将hello
模块引入:
>>> import hello
再用dir()
函数,来查看当前环境可用的函数/变量
:
>>> dir() ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'hello', 's']
能够看到,多了一个hello
。这是由于引入的模块会使用模块名
来做为可用的标识符。
咱们能够用dir(hello)
来查看hello
模块支持的函数/变量
:
>>> dir(hello) ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'PY', 'hello_py']
能够看到,有两个标识符PY
和 hello_py
可使用,但并不能看出PY
和hello_py
是一个函数,仍是一个变量。
能够经过type(hello.标识符)
来查看标识符的类型:
>>> type(hello.PY) # 字符串 <class 'str'> >>> type(hello.hello_py) # 函数 <class 'function'>
可见PY
是一个字符串, hello_py
是一个函数。
注意:
引用一个模块中的
标识符
,使用的是点.
操做符好比这里的
hello.PY
和hello.hello_py
咱们能够这样来调用一个模块中的函数/变量
:
>>> hello.PY 'Hi Python.' >>> hello.hello_py() hello python.
咱们知道编写函数时能够有文档注释,一样模块中也能够有文档注释
,任何模块的第一个字符串将做为该模块的文档注释,以下:
#! /usr/bin/env python3 '''这是hello 模块的说明文档''' # 定义一个字符串 PY = 'Hi Python.' # 定义一个函数 def hello_py(): print('Hello Python.')
能够用魔法方法__doc__
来访问文档字符串:
>>> hello.__doc__ '这是hello 模块的说明文档'
在Python 模块中,规定以单下划线_
和双下划线__
开头的函数/变量
,被称为私有函数/变量
(private),不该该被外部模块使用。
不以_
和__
开头的函数/变量
,被称为共有函数/变量
(public),可被外部使用。
以下:
#! /usr/bin/env python3 '''这是hello 模块的说明文档''' PY = 'Hi Python.' def _hello(s): print('hello %s.' % s) def hello_py(): _hello('python') def hello_java(): _hello('java')
在该模块中,hello_py
,hello_java
和 PY
是提供给外部使用的,而_hello
只建议在模块内部使用。
其实在Python 中的这种访问权限
的控制,其实是“假的”,由于从技术上来讲,这种方式,并不能彻底的禁止外部调用,只是至关于一种编程规范
。
若是咱们非要使用这种以下划线
开头的函数,从技术上来讲也是行得通的,以下:
>>> import hello >>> hello._hello('python') hello python.
但通常咱们并不建议这样作。
__name__
属性每一个模块中都自带一个__name__
属性,运行当前模块时,该属性的值为__main__
,这常常与if 语句
一块儿,被用来测试代码
使用,这相似其它编程语言中的main()
函数。
以下,文件名为hello.py
:
#! /usr/bin/env python3 '''这是hello 模块的说明文档''' PY = 'Hi Python.' def hello_py(): print('hello python.') if __name__ == '__main__': hello_py()
当咱们在命令行执行python3 hello.py
时,if __name__ == '__main__':
内的代码块都会被执行。
但当在其它模块引入hello
模块时,if __name__ == '__main__':
内的代码块并不会被执行。
Python 包是比模块更高层的概念,一个Python 包中能够包含一个或多个模块。
一个包含多个模块的Python 包结构以下:
my_abc/ ├── __init__.py ├── a.py ├── b.py └── c/ ├── __init__.py └── d.py
my_abc
是顶层包名,my_abc
目录中有一个__init__.py
文件,拥有这个__init__.py
文件的目录才会被认为是一个Python 包,不然,只是一个普通的目录。
__init__.py
文件能够为空,也能够有Python 代码,my_abc/c/
目录中的__init__.py
文件也是一样的道理。
向my_abc/__init__.py
文件中写入以下内容:
#! /usr/bin/env python3 print('这是my_abc 模块中的 __init__ 文件')
向my_abc/c/__init__.py
文件中写入以下内容:
#! /usr/bin/env python3 print('这是my_abc.c 模块中的 __init__ 文件')
咱们在my_abc
同级目录下运行python3
解释器,当咱们引入my_abc
包时,my_abc/__init__.py
文件中的代码就会被执行:
>>> import my_abc # 第一次引入 这是my_abc 模块中的 __init__ 文件 >>> import my_abc # 第二次引入
能够看到当输入import my_abc
代码时,字符串这是my_abc 模块中的 __init__ 文件
被输出,说明my_abc/__init__.py
文件中的内容被执行了。
紧接着再次输入import my_abc
代码时,并无任何输出,说明某个模块中的__init__.py
文件中的内容,只有在第一次导入该模块时,才会执行。
此时,当前环境中多了一个可用的my_abc
标识符:
>>> dir() ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'my_abc']
一样,当咱们引入my_abc.c
包时,my_abc/c/__init__.py
文件中的代码就会被执行:
>>> import my_abc.c 这是my_abc.c 模块中的 __init__ 文件
from ... import ...
语法
咱们可使用from... import...
语法来引入一个包中的模块,好比咱们引入my_abc
包中的a
模块,以下:
>>> from my_abc import a 这是my_abc 模块中的 __init__ 文件 >>> dir() ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a']
能够看到,使用该语法引入a
模块时,my_abc/__init__.py
文件中的内容也执行了,此时,当前环境中多了一个可用的a
标识符。
from ... import ... as...
语法
可使用as
关键字为模块重命名,例如将a
模块重命名为a_test
:
>>> from my_abc import a as a_test 这是my_abc 模块中的 __init__ 文件 >>> dir() ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a_test']
能够看到本次导入时,没有a
标识符,取而代之的a_test
。
from ... import *
语法
from ... import *
语法会导入某个包中__init__.py
文件内的__all__
列表的全部内容,当__all__
列表不存在时,该语法将导入__init__.py
文件中的全部可用标识符。
例如,my_abc/__init__.py
文件中内容以下,没有__all__
列表:
#! /usr/bin/env python3 print('这是my_abc 模块中的 __init__ 文件') i = 1 j = 2 def hello(): print('hello')
使用from ... import *
语法,将导入__init__.py
文件中全部可用的标识符:
>>> from my_abc import * 这是my_abc 模块中的 __init__ 文件 >>> dir() ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'hello', 'i', 'j']
可见__init__.py
文件中的全部可用标识符,都被导入到了当前环境中。
若是在__init__.py
文件中声明一个__all__
列表,以下:
#! /usr/bin/env python3 print('这是my_abc 模块中的 __init__ 文件') __all__ = ['i', 'hello'] i = 1 j = 2 def hello(): print('hello')
from ... import *
语法将只会导入__all__
列表中的内容,以下
>>> from my_abc import * 这是my_abc 模块中的 __init__ 文件 >>> dir() ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'hello', 'i']
由于__all__
列表中只有i
, hello
两个元素,因此只导入了这两个标识符。
从内建模块sys
中的path
标识符可查看导入模块的路径:
>>> import sys >>> sys.path ['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']
其中,第一个''
表示从当前目录
中导入,其它的目录是系统中的标准包路径
。
Python 会按照该列表,从前日后依次从这些路径中导入你想import
的模块,先从当前目录中尝试导入你想导入的模块,若是没有找到,会依次从后边的路径去查找,若是都没有找到,最后会抛出异常。
好比,如今有一个test
目录,该目录下有一个a.py
文件:
test/ └── a.py
若是在test
同级目录下导入a.py
,将出现异常,由于没法从sys.path
中找到a.py
:
>>> import a Traceback (most recent call last): File "<stdin>", line 1, in <module> ModuleNotFoundError: No module named 'a'
此时,能够将./test
目录append
到sys.path
中,而后再import
:
>>> import sys >>> sys.path.append('./test') >>> import a # 没有出现异常,说明导入成功 >>> dir() ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'sys'] # a 模块被成功导入
(完。)
推荐阅读:
Python 简明教程 --- 14,Python 数据结构进阶
Python 简明教程 --- 16,Python 高阶函数
欢迎关注做者公众号,获取更多技术干货。