Python import 用法

常规导入

模块 Modules

一个 py 文件即相当于一个模块 Module;它可以被其他 py 导入,以便复用其中的代码;

1
2
import math
math.pi()

被导入的 py 文件,同时充当了一个命名空间(Namespace),可通过该命名空间访问其内部的变量和函数;

当使用 from A import B 时,就把 B 导入到全局命名空间中了,这个时候并没有导入 A;而且导入时 B 还可以重命名 B,例如:

1
from math import pi as PI

包 Packages

Pacage 也是一个模块,它跟普通模块的区别在于它内部包含了其他模块或者其他 Package

Python 官方文档对 Package 的解释为,当一个模块的内置 path 属性有值时,即是一个 Package;个人感觉包和模块很像目录和文件的关系;

实际使用中,Package 通常是一个包含 py 文件和子目录的文件夹;当给某个文件夹中添加一个 init 文件时,它就变成了一个 pakcage;init 文件中可以放置内容,它表示当 package 被作为模块导入时,该模块包含的内容;它可以为空;

当一个文件夹没有 init 文件时,它仍然会被 Python 解释器视作一个 Package,只是它不是普通的 Package,而是一个特殊的 package,称为命名空间 Package;

通常在导入一个包时,并不导入它里面的子模块和子包。

发现一个有意思的点,当使用 from A import B 时,虽然 A 没有导入进来,但是 B 和 A 的上下级关系是存在的。因此如果有另外一行代表导入了 A,那么即使 A 的 init 文件中没有导入 B,也仍然可以通过 A.B 来访问 B;

使用 import A.B.C 来导入时,A.B. 表示的是路径关系好像;而且一旦导入成功,B 和 C 的上下级关系就建立了;即使 B 的 init 文件中原本默认没有导入 C,也因为这种关系的建立,使得 B.C 的访问能够成功;

当一个包中的 init 文件为空时,那么导入这个包时,只导入了一个命名空间,并未导入任何具体的模块;

注意:当导入一个模块时,除了会导入模块中的内容外,还会同时创建一个包含该内容的命名空间;当使用不同的导入方法时,同一个模块可以隶属于不同的命名空间;即可以通过多个命名空间访问到相同的模块;

模块本质上面是一个对象,因此可以通过对象的内置方法来访问来模块中的内容,示例如下:

1
2
import math
math.__dict__['pi']

在 init 文件中导入包中的模块,可以让包的使用者更方便的使用这些模块,而无须记住相应的路径

绝对导入和相对导入

如果代码只在本地使用,不需要共享给他人使用时,使用绝对路径导入是一个不错的方法。但是如果它成为一个包,需要被其他人复用时,那么使用绝对路径就会报错了,此时需要在包中使用相对路径。同时引用该包的人,可通过 pip 安装该包。安装后,包就会被存放在默认的 site_packages 文件夹中,这样在运行脚本时就可以被解释器找到;不然就得修改 PYTHONPATH 环境变量或者调用 sys.path 方法添加包的路径;

当解释器遇到 import 语句时,它会到三个地方寻找包,分别如下:

  • 当前脚本所在的目录;
  • 环境变量 PYTHONPATH 指向的目录;
  • pip 存放依赖的目录;

安装本地包

添加配置文件 setup.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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import io
import os
import sys
from shutil import rmtree

from setuptools import find_packages, setup, Command

# Package meta-data.
NAME = 'mypackage'
DESCRIPTION = 'My short description for my project.'
URL = 'https://github.com/me/myproject'
EMAIL = 'me@example.com'
AUTHOR = 'Awesome Soul'
REQUIRES_PYTHON = '>=3.6.0'
VERSION = '0.1.0'

# What packages are required for this module to be executed?
REQUIRED = [
# 'requests', 'maya', 'records',
]

# What packages are optional?
EXTRAS = {
# 'fancy feature': ['django'],
}

# The rest you shouldn't have to touch too much :)
# ------------------------------------------------
# Except, perhaps the License and Trove Classifiers!
# If you do change the License, remember to change the Trove Classifier for that!

here = os.path.abspath(os.path.dirname(__file__))

# Import the README and use it as the long-description.
# Note: this will only work if 'README.md' is present in your MANIFEST.in file!
try:
with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
long_description = '\n' + f.read()
except FileNotFoundError:
long_description = DESCRIPTION

# Load the package's __version__.py module as a dictionary.
about = {}
if not VERSION:
project_slug = NAME.lower().replace("-", "_").replace(" ", "_")
with open(os.path.join(here, project_slug, '__version__.py')) as f:
exec(f.read(), about)
else:
about['__version__'] = VERSION

# Where the magic happens:
setup(
name=NAME,
version=about['__version__'],
description=DESCRIPTION,
long_description=long_description,
long_description_content_type='text/markdown',
author=AUTHOR,
author_email=EMAIL,
python_requires=REQUIRES_PYTHON,
url=URL,
packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]),
# If your package is a single module, use this instead of 'packages':
# py_modules=['mypackage'],

# entry_points={
# 'console_scripts': ['mycli=mymodule:cli'],
# },
install_requires=REQUIRED,
extras_require=EXTRAS,
include_package_data=True,
license='MIT',
classifiers=[
# Trove classifiers
# Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy'
],
# $ setup.py publish support.
cmdclass={
'upload': UploadCommand,
},
)

安装命令

1
python -m pip install -e .

Resources 导入

在 3.7 版本之后,静态资源文件也支持像包一样处理,只需要在资源所有的文件中添加一个 init 文件即可;然后引入包后,只需要使用内置的 importlib.resources 模块,即可实现对资源文件的读取

假设包中有如下资源:

1
2
3
4
5
books/

├── __init__.py
├── alice_in_wonderland.png
└── alice_in_wonderland.txt

则可以通过如下方式读取其中的资源文件:

1
2
3
4
from importlib import resources

with resources.open_text("books", "alice.txt") as fid:
alice = fid.readlines()

示例二:

1
2
3
4
data/

├── __init__.py
└── WPP2019_TotalPopulationBySex.csv
1
2
3
4
from importlib import resources

with resources.open_text("data", "WPP2019_TotalPopulationBySex.csv") as fid:
rows = csv.DictReader(fid)

Python import 用法
https://ccw1078.github.io/2022/03/13/Python import 用法/
作者
ccw
发布于
2022年3月13日
许可协议