Python 3:模块


#Python#


【编写中】

1、模块是什么?

模块一种组织代码的形式。当代码规模变大后,需要将代码拆分到多个 Python 源代码文件中。对于一个程序,运行的入口一般只有一个,那么,除了程序入口之外的所有源文件,都是模块。

2、非package下的源文件导入模块的顺序

顺序是:

  1. 被执行源文件所在目录下的模块
  2. PYTHONPATH 环境变量指定的目录
  3. Python 自带的标准模块
  4. 安装在 site-packages 下的第三方模块
  5. .pth后缀文件中配置的目录

这些最终会在 sys.path 中体现出来。

示例2.1

在 py-project 目录下创建文件 main.py:

py-project
└── main.py
import sys
for path in sys.path:
    print(path)

运行:

$ python3 main.py
/Users/letian/Desktop/py-project
/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python36.zip
/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6
/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload
/Users/letian/Library/Python/3.6/lib/python/site-packages
/usr/local/lib/python3.6/site-packages

$ cd ..
$ python3 py-project/main.py
/Users/letian/Desktop/py-project
/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python36.zip
/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6
/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload
/Users/letian/Library/Python/3.6/lib/python/site-packages
/usr/local/lib/python3.6/site-packages

示例2.2

项目结构:

py-project
├── main.py
└── module.py

module.py 内容如下:

def get_name():
    return "python"

main.py 内容如下:

import module

print(module.get_name())

运行:

$ python3 main.py 
python

$ cd ..
$ python3 py-project/main.py 
python

示例2.3

项目结构:

py-project
└── main.py

main.py 内容如下:

import string  // python 自带模块

print(string)

运行:

$ python3 main.py
<module 'string' from '/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/string.py'>

如果 py-project 目录中也有一个 string 模块呢? 添加 string.py,项目结构变成:

py-project
├── main.py
└── string.py

执行 main.py:

$ python3 main.py
<module 'string' from '/Users/letian/Desktop/py-project/string.py'>

可以看到,优先使用了自定义的 string 模块。

3、package下的源文件导入顺序

当一个目录中存在 __init__.py 文件时,那么这个目录就是一个 package。如果子目录也有 __init__.py 文件,那么子目录就是一个子 package。

示例3.1

项目结构:

py-project
└── dev
    ├── __init__.py
    ├── main.py
    └── string.py

main.py 内容如下:

import string

print(string)

运行:

$ cd dev
$ python3 main.py
<module 'string' from '/Users/letian/Desktop/py-project/dev/string.py'>

$ cd ..
$ python3 dev/main.py
<module 'string' from '/Users/letian/Desktop/py-project/dev/string.py'>

但是,如果以模块的形式运行,结果会有不同:

$ python3 -m dev.main
<module 'string' from '/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/string.py'>

也就是,以模块的形式运行时,优先使用Python内置模块

4、不能直接执行的场景

示例4.1

项目结构:

py-project
└── dev
    ├── __init__.py
    ├── main.py
    └── string.py

main.py 内容如下:

from dev import string

print(string)

以下方式会失败:

$ python3 dev/main.py
Traceback (most recent call last):
  File "dev/main.py", line 1, in <module>
    from dev import string
ModuleNotFoundError: No module named 'dev'

$ cd dev
$ python3 main.py
Traceback (most recent call last):
  File "main.py", line 1, in <module>
    from dev import string
ModuleNotFoundError: No module named 'dev'

以下方式会成功:

$ PYTHONPATH="." python3 dev/main.py
<module 'dev.string' from '/Users/letian/Desktop/py-project/dev/string.py'>

$ python3 -m dev.main
<module 'dev.string' from '/Users/letian/Desktop/py-project/dev/string.py'>

示例4.2

项目结构:

py-project
└── dev
    ├── __init__.py
    ├── main.py
    └── string.py

main.py 内容如下:

from . import string

print(string)

以下方式会失败:

$ python3 dev/main.py
Traceback (most recent call last):
  File "dev/main.py", line 1, in <module>
    from . import string
ImportError: cannot import name 'string'

$ PYTHONPATH="." python3 dev/main.py
Traceback (most recent call last):
  File "dev/main.py", line 1, in <module>
    from . import string
ImportError: cannot import name 'string'

$ cd dev
$ python3 main.py
Traceback (most recent call last):
  File "main.py", line 1, in <module>
    from . import string
ImportError: cannot import name 'string'

以下方式会成功:

$ python3 -m dev.main
<module 'dev.string' from '/Users/letian/Desktop/py-project/dev/string.py'>

5、其他示例

我们在~/Desktop创建py-project目录,并在其中添加一些 Python 代码:

py-project
├── dev
│   ├── __init__.py
│   ├── util.py
│   ├── main2.py
│   ├── main3.py
│   └── main4.py
└── main1.py

dev 目录中含有__init__.py,所以dev是一个module。

dev/util.py 内容:

def get_name():
    return "乐天的开发教程"

dev/main2.py 内容:

from .util import get_name

print(get_name())

dev/main3.py 内容:

from dev.util import get_name

print(get_name())

dev/main4.py 内容:

from util import get_name

print(get_name())

main1.py 内容:

from dev.util import get_name

print(get_name())

在 py-project 目录执行:

$ cd py-project
$ python3 main1.py
乐天的开发教程
$ python3 dev/main2.py
Traceback (most recent call last):
  File "dev/main2.py", line 1, in <module>
    from .util import get_name
ModuleNotFoundError: No module named '__main__.util'; '__main__' is not a package
$ python3 dev/main3.py
Traceback (most recent call last):
  File "dev/main3.py", line 1, in <module>
    from dev.util import get_name
ModuleNotFoundError: No module named 'dev'
$ python3 dev/main4.py
乐天的开发教程
$ python3 -m dev.main2
乐天的开发教程

$ python3 -m dev.main3
乐天的开发教程

在 py-project/dev 目录执行:

$ cd py-project/dev
$ python3 main2.py
Traceback (most recent call last):
  File "main2.py", line 1, in <module>
    from .util import get_name
ModuleNotFoundError: No module named '__main__.util'; '__main__' is not a package
$ python3 main3.py
Traceback (most recent call last):
  File "main3.py", line 1, in <module>
    from dev.util import get_name
ModuleNotFoundError: No module named 'dev'
$ python3 main4.py
乐天的开发教程
$ python3 ../main1.py
乐天的开发教程
$ python3 -m main2
Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/Users/letian/Desktop/py-project/dev/main2.py", line 1, in <module>
    from .util import get_name
ImportError: attempted relative import with no known parent package
$ python3 -m main3
Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/Users/letian/Desktop/py-project/dev/main3.py", line 1, in <module>
    from dev.util import get_name
ModuleNotFoundError: No module named 'dev'

( 本文完 )