提示:文章尚未写完,感觉一开始的代码分类没有做好,有所遗漏,所以这一篇就停在这里,重开一篇:点击查看。
前言
提示:本文要记录的大概内容:
import statement 并不复杂,无非就是几种格式而已。导入 Python 标准库,只要合乎格式就可以了。但是,导入自定义 module 却常常出错。尤其是在 Anaconda (Spyder)上写成的代码,换到 PyCharm 就不行了,或者换成 IDLE 用命令行执行也是报错。
深入了解这个问题,着实花了我3天时间。故此,记录如下。
提示:以下是本篇文章正文内容,下面案例可供参考
1 import statement
1.1. 官方规范
这是官方规范。
2 常见格式
2.1. 导入标准库
import tkinter
import turtle as t
from tkinter.ttk import Combobox as Cx
from tkinter import *
type(tkinter)
module
type(tkinter.ttk)
module
type(tkinter.ttk.Combobox)
type
type(tkinter.ttk.Combobox.xview)
function
type(tkinter.mainloop)
function
import tkinter.ttk
import tkinter.ttk.Combobox
ModuleNotFoundError: No module named 'tkinter.ttk.Combobox'; 'tkinter.ttk' is not a package
import tkinter.ttk.Combobox.xview
ModuleNotFoundError: No module named 'tkinter.ttk.Combobox'; 'tkinter.ttk' is not a package
import tkinter.mainloop
ModuleNotFoundError: No module named 'tkinter.mainloop'
from tkinter import ttk
from tkinter import *
from tkinter.ttk import Combobox
from tkinter.ttk import *
from tkinter.ttk.Combobox import xview
ModuleNotFoundError: No module named 'tkinter.ttk.Combobox'; 'tkinter.ttk' is not a package
from tkinter.ttk.Combobox import *
ModuleNotFoundError: No module named 'tkinter.ttk.Combobox'; 'tkinter.ttk' is not a package
from tkinter import mainloop
2.2. 导入自定义库
其实,这次笔记的核心是一定要设置 PYTHONPATH 变量,所以先查看一下两个解释器的环境变量。
2.2.1. 查看 Spyder 的 PYTHONPATH 变量
空的,容易说明问题。
2.2.2. 查看 Spyder 的 sys.path
import sys
for path in sys.path:
print(path)
print(len(sys.path))
2.2.3. 查看 PyCharm 的 PYTHONPATH 变量
其实,重要的不是查看,而是设置。如下图,很重要。
2.2.4. 查看 PyCharm 的 sys.path
尽管 PyCharm 调用 Anaconda 的包,但二者的环境变量仍然各自独立。
2.3. 绝对导入(absolute import)与相对导入(relative import)
- 看起来很麻烦的两个概念,但纠结这个毫无意义。如果包的 __ init__.py 是空文件,那么就不要用 . 起头的相对导入。除非你懂得如何设置 __ init__.py。
- 相对导入必须设置好才能用,否则提示 SyntaxError
- 相对导入用 . 起头,使用前缀点号,而且只有一种形式:from <> import <>
- 绝对导入可用 import <> 或 from <> import <> 语法
2.4. 在未设置 PYTHONPATH 变量的前提下,不同 IDLE 的表现
2.4.1. 创建层级目录
3个 modules 的代码如下:
class Class:
"""module2.py"""
def __init__(self):
print("module2.Class")
def test_func1(self):
print("method module2.Class.test_func1")
def test_func2(self):
print("method module2.Class.test_func2")
def test_func3(self):
print("method module2.Class.test_func3")
class Class:
"""module1.py"""
def __init__(self):
print("module1.Class")
def test_func1(self):
print("method module1.Class.test_func1")
def test_func2(self):
print("method module1.Class.test_func2")
def test_func3(self):
print("method module1.Class.test_func3")
class Class:
"""module0.py"""
def __init__(self):
print("module0.Class")
def test_func1(self):
print("method module0.Class.test_func1")
def test_func2(self):
print("method module0.Class.test_func2")
def test_func3(self):
print("method module0.Class.test_func3")
2.4.2. Spyder 的表现
import sys
print(len(sys.path))
12
from . import module0
from .. import module0
from .module0 import Class
import pkg.module0.Class
import pkg.module0
import module0
from pkg.module0 import Class
from pkg import module0
from module0 import Class
from . import module1
from .. import module1
from ... import module1
from .module1 import Class
import .module1
import pkg.pkg1.module1.Class
import pkg.pkg1.module1
import pkg.pkg1
import pkg1.module1.Class
import pkg1.module1
import pkg1
from pkg.pkg1.module1 import Class
from pkg.pkg1 import module1
from pkg import pkg1.module1
import module2
import .module2
import ..module2
import ...module2
from .import module2
from ..import module2
from ...import module2
import pkg
import pkg.pkg1
import pkg.pkg1.pkg2
import pkg.pkg1.pkg2.module2
import pkg.pkg1.pkg2.module2.Class
import pkg1
import pkg1.pkg2
import pkg1.pkg2.module2
from pkg import module2.Class
from pkg import module2
from pkg import module1
from pkg.pkg1.pkg2 import module2
from pkg.pkg1 import module1
from pkg import module0
from pkg.pkg1.pkg2.module2 import Class
from pkg.pkg1.module1 import Class
from pkg.module0 import Class
2.4.3. PyCharm 的表现
红色波浪线提示 SyntaxError 那么就逐行试验一下能不能导入:
import sys
print(len(sys.path))
10
from . import module0
from .. import module0
from .module0 import Class
import pkg.module0.Class
import pkg.module0
import module0
from pkg.module0 import Class
from pkg import module0
from module0 import Class
from . import module1
from .. import module1
from ... import module1
from .module1 import Class
import .module1
import pkg.pkg1.module1.Class
import pkg.pkg1.module1
import pkg.pkg1
import pkg1.module1.Class
import pkg1.module1
import pkg1
from pkg.pkg1.module1 import Class
from pkg.pkg1 import module1
from pkg import pkg1.module1
import module2
import .module2
import ..module2
import ...module2
from .import module2
from ..import module2
from ...import module2
import pkg
import pkg.pkg1
import pkg.pkg1.pkg2
import pkg.pkg1.pkg2.module2
import pkg.pkg1.pkg2.module2.Class
import pkg1
import pkg1.pkg2
import pkg1.pkg2.module2
from pkg import module2.Class
from pkg import module2
from pkg import module1
from pkg.pkg1.pkg2 import module2
from pkg.pkg1 import module1
from pkg import module0
from pkg.pkg1.pkg2.module2 import Class
from pkg.pkg1.module1 import Class
from pkg.module0 import Class
两相对比,在 Spyder 里可以导入的语句, 与在 PyCharm 里可以导入的语句,没有任何重叠。当然,前提是都未设置 PYTHONPATH 变量。
2.4.4. Python IDLE 3.8 的表现
Python IDLE 里执行的结果居然与 Spyder 完全相同,惊了我!
from . import module0
from .. import module0
from .module0 import Class
import pkg.module0.Class
import pkg.module0
import module0
from pkg.module0 import Class
from pkg import module0
from module0 import Class
from . import module1
from .. import module1
from ... import module1
from .module1 import Class
import .module1
import pkg.pkg1.module1.Class
import pkg.pkg1.module1
import pkg.pkg1
import pkg1.module1.Class
import pkg1.module1
import pkg1
from pkg.pkg1.module1 import Class
from pkg.pkg1 import module1
from pkg import pkg1.module1
import module2
import .module2
import ..module2
import ...module2
from .import module2
from ..import module2
from ...import module2
import pkg
import pkg.pkg1
import pkg.pkg1.pkg2
import pkg.pkg1.pkg2.module2
import pkg.pkg1.pkg2.module2.Class
import pkg1
import pkg1.pkg2
import pkg1.pkg2.module2
from pkg import module2.Class
from pkg import module2
from pkg import module1
from pkg.pkg1.pkg2 import module2
from pkg.pkg1 import module1
from pkg import module0
from pkg.pkg1.pkg2.module2 import Class
from pkg.pkg1.module1 import Class
from pkg.module0 import Class
2.5. 为三个 IDLE 的 PYTHONPATH 变量都添加 pkg 目录,并查看其导入语句
2.5.1. 为三个 IDLE 的 PYTHONPATH 变量都添加 pkg 目录
2.5.1.1. 为 Spyder 的 PYTHONPATH 变量添加 pkg 目录
2.5.1.2. 为 PyCharm 的 PYTHONPATH 变量添加 pkg 目录
2.5.1.3. 为 Python IDLE 的 PYTHONPATH 变量添加 pkg 目录
尝试用另外一种方法添加目录:
2.5.2. 查看三个 IDLE 的导入语句
2.5.2.1. 查看 Spyder 的导入语句
from . import module0
from .. import module0
from .module0 import Class
import pkg.module0.Class
import pkg.module0
import module0
from pkg.module0 import Class
from pkg import module0
from module0 import Class
from . import module1
from .. import module1
from ... import module1
from .module1 import Class
import .module1
import pkg.pkg1.module1.Class
import pkg.pkg1.module1
import pkg.pkg1
import pkg1.module1.Class
import pkg1.module1
import pkg1
from pkg.pkg1.module1 import Class
from pkg.pkg1 import module1
from pkg import pkg1.module1
import module2
import .module2
import ..module2
import ...module2
from .import module2
from ..import module2
from ...import module2
import pkg
import pkg.pkg1
import pkg.pkg1.pkg2
import pkg.pkg1.pkg2.module2
import pkg.pkg1.pkg2.module2.Class
import pkg1
import pkg1.pkg2
import pkg1.pkg2.module2
from pkg import module2.Class
from pkg import module2
from pkg import module1
from pkg.pkg1.pkg2 import module2
from pkg.pkg1 import module1
from pkg import module0
from pkg.pkg1.pkg2.module2 import Class
from pkg.pkg1.module1 import Class
from pkg.module0 import Class
2.5.2.2. 查看 PyCharm 的导入语句
2.5.2.3. 查看 Python IDLE 的导入语句
2.6. 为三个 IDLE 的 PYTHONPATH 变量都添加 pkg.pkg1 目录,并查看其导入语句
2.6.1. 为三个 IDLE 的 PYTHONPATH 变量都添加 pkg.pkg1 目录
2.6.1.1. 为 Spyder 的 PYTHONPATH 变量添加 pkg.pkg1 目录
2.6.1.2. 为 PyCharm 的 PYTHONPATH 变量添加 pkg.pkg1 目录
2.6.1.3. 为 Python IDLE 的 PYTHONPATH 变量添加 pkg.pkg1 目录
2.6.2. 查看三个 IDLE 的导入语句
2.6.2.1. 查看 Spyder 的导入语句
2.6.2.1.1.脚本文件在 pkg 目录
from . import module0
from .. import module0
from .module0 import Class
import pkg.module0.Class
import pkg.module0
import module0
from pkg.module0 import Class
from pkg import module0
from module0 import Class
from . import module1
from .. import module1
from ... import module1
from .module1 import Class
import .module1
import pkg.pkg1.module1.Class
import pkg.pkg1.module1
import pkg.pkg1
import pkg1.module1.Class
import pkg1.module1
import pkg1
from pkg.pkg1.module1 import Class
from pkg.pkg1 import module1
from pkg import pkg1.module1
import module2
import .module2
import ..module2
import ...module2
from .import module2
from ..import module2
from ...import module2
import pkg
import pkg.pkg1
import pkg.pkg1.pkg2
import pkg.pkg1.pkg2.module2
import pkg.pkg1.pkg2.module2.Class
import pkg1
import pkg1.pkg2
import pkg1.pkg2.module2
from pkg import module2.Class
from pkg import module2
from pkg import module1
from pkg.pkg1.pkg2 import module2
from pkg.pkg1 import module1
from pkg import module0
from pkg.pkg1.pkg2.module2 import Class
from pkg.pkg1.module1 import Class
from pkg.module0 import Class
经对比,可导入的语句及错误提示与 pkg 目录加入 PYTHONPATH 变量时相同。
2.6.2.1.2.脚本文件在 pkg.pkg1 目录
from . import module0
from .. import module0
from .module0 import Class
import pkg.module0.Class
import pkg.module0
import module0
from pkg.module0 import Class
from pkg import module0
from module0 import Class
from . import module1
from .. import module1
from ... import module1
from .module1 import Class
import .module1
import pkg.pkg1.module1.Class
import pkg.pkg1.module1
import pkg.pkg1
import pkg1.module1.Class
import pkg1.module1
import pkg1
from pkg.pkg1.module1 import Class
from pkg.pkg1 import module1
from pkg import pkg1.module1
import module2
import .module2
import ..module2
import ...module2
from .import module2
from ..import module2
from ...import module2
import pkg
import pkg.pkg1
import pkg.pkg1.pkg2
import pkg.pkg1.pkg2.module2
import pkg.pkg1.pkg2.module2.Class
import pkg1
import pkg1.pkg2
import pkg1.pkg2.module2
from pkg import module2.Class
from pkg import module2
from pkg import module1
from pkg.pkg1.pkg2 import module2
from pkg.pkg1 import module1
from pkg import module0
from pkg.pkg1.pkg2.module2 import Class
from pkg.pkg1.module1 import Class
from pkg.module0 import Class
2.6.2.1.3. 总结
经对比,可导入的语句及错误提示与 pkg 目录加入 PYTHONPATH 变量时相同,当然也就与脚本文件在 pkg 目录或 pkg1 目录无关。
2.6.2.2. 查看 PyCharm 的导入语句
2.6.2.2.1.脚本文件在 pkg.pkg1 目录
from . import module0
from .. import module0
from .module0 import Class
import pkg.module0.Class
import pkg.module0
import module0
from pkg.module0 import Class
from pkg import module0
from module0 import Class
from . import module1
from .. import module1
from ... import module1
from .module1 import Class
import .module1
import pkg.pkg1.module1.Class
import pkg.pkg1.module1
import pkg.pkg1
import pkg1.module1.Class
import pkg1.module1
import pkg1
from pkg.pkg1.module1 import Class
from pkg.pkg1 import module1
from pkg import pkg1.module1
import module2
import .module2
import ..module2
import ...module2
from .import module2
from ..import module2
from ...import module2
import pkg
import pkg.pkg1
import pkg.pkg1.pkg2
import pkg.pkg1.pkg2.module2
import pkg.pkg1.pkg2.module2.Class
import pkg1
import pkg1.pkg2
import pkg1.pkg2.module2
from pkg import module2.Class
from pkg import module2
from pkg import module1
from pkg.pkg1.pkg2 import module2
from pkg.pkg1 import module1
from pkg import module0
from pkg.pkg1.pkg2.module2 import Class
from pkg.pkg1.module1 import Class
from pkg.module0 import Class
2.6.2.2.1.脚本文件在 pkg.pkg1 目录
这个就厉害了!连一个可导入的语句都没有!而且全部红色波浪线!
from . import module0
from .. import module0
from .module0 import Class
import pkg.module0.Class
import pkg.module0
import module0
from pkg.module0 import Class
from pkg import module0
from module0 import Class
from . import module1
from .. import module1
from ... import module1
from .module1 import Class
import .module1
import pkg.pkg1.module1.Class
import pkg.pkg1.module1
import pkg.pkg1
import pkg1.module1.Class
import pkg1.module1
import pkg1
from pkg.pkg1.module1 import Class
from pkg.pkg1 import module1
from pkg import pkg1.module1
import module2
import .module2
import ..module2
import ...module2
from .import module2
from ..import module2
from ...import module2
import pkg
import pkg.pkg1
import pkg.pkg1.pkg2
import pkg.pkg1.pkg2.module2
import pkg.pkg1.pkg2.module2.Class
import pkg1
import pkg1.pkg2
import pkg1.pkg2.module2
from pkg import module2.Class
from pkg import module2
from pkg import module1
from pkg.pkg1.pkg2 import module2
from pkg.pkg1 import module1
from pkg import module0
from pkg.pkg1.pkg2.module2 import Class
from pkg.pkg1.module1 import Class
from pkg.module0 import Class
2.6.2.2.3. 总结
经对比,可导入的语句及错误提示与 pkg 目录加入 PYTHONPATH 变量时相同,当然也就与脚本文件在 pkg 目录或 pkg1 目录无关。
2.6.2.3. 查看 Python IDLE 的导入语句
这个我就忽略了,烦了。
2.7. 为三个 IDLE 的 PYTHONPATH 变量都添加 pkg.pkg1.pkg2 目录,并查看其导入语句
2.7.1. 为三个 IDLE 的 PYTHONPATH 变量都添加 pkg.pkg1.pkg2 目录
2.7.1.1. 为 Spyder 的 PYTHONPATH 变量添加 pkg.pkg1.pkg2 目录
2.7.1.2. 为 PyCharm 的 PYTHONPATH 变量添加 pkg.pkg1.pkg2 目录
2.7.1.3. 为 Python IDLE 的 PYTHONPATH 变量添加 pkg.pkg1.pkg2 目录
2.7.2. 查看三个 IDLE 的导入语句
2.7.2.1. 查看 Spyder 的导入语句
2.7.2.1.1. 脚本文件在 pkg 目录
from . import module0
from .. import module0
from .module0 import Class
import pkg.module0.Class
import pkg.module0
import module0
from pkg.module0 import Class
from pkg import module0
from module0 import Class
from . import module1
from .. import module1
from ... import module1
from .module1 import Class
import .module1
import pkg.pkg1.module1.Class
import pkg.pkg1.module1
import pkg.pkg1
import pkg1.module1.Class
import pkg1.module1
import pkg1
from pkg.pkg1.module1 import Class
from pkg.pkg1 import module1
from pkg import pkg1.module1
import module2
import .module2
import ..module2
import ...module2
from .import module2
from ..import module2
from ...import module2
import pkg
import pkg.pkg1
import pkg.pkg1.pkg2
import pkg.pkg1.pkg2.module2
import pkg.pkg1.pkg2.module2.Class
import pkg1
import pkg1.pkg2
import pkg1.pkg2.module2
from pkg import module2.Class
from pkg import module2
from pkg import module1
from pkg.pkg1.pkg2 import module2
from pkg.pkg1 import module1
from pkg import module0
from pkg.pkg1.pkg2.module2 import Class
from pkg.pkg1.module1 import Class
from pkg.module0 import Class
2.7.2.1.2. 脚本文件在 pkg.pkg1 目录
2.7.2.1.3. 脚本文件在 pkg.pkg1.pkg2 目录
2.7.2.1.4. 总结
无论脚本文件在 pkg or pkg1 or pkg2,能导入的语句相同,但错误提示略有不同
2.7.2.2. 查看 PyCharm 的导入语句
2.7.2.2.1. 脚本文件在 pkg 目录
from . import module0
from .. import module0
from .module0 import Class
import pkg.module0.Class
import pkg.module0
import module0
from pkg.module0 import Class
from pkg import module0
from module0 import Class
from . import module1
from .. import module1
from ... import module1
from .module1 import Class
import .module1
import pkg.pkg1.module1.Class
import pkg.pkg1.module1
import pkg.pkg1
import pkg1.module1.Class
import pkg1.module1
import pkg1
from pkg.pkg1.module1 import Class
from pkg.pkg1 import module1
from pkg import pkg1.module1
import module2
import .module2
import ..module2
import ...module2
from . import module2
from .. import module2
from ... import module2
import pkg
import pkg.pkg1
import pkg.pkg1.pkg2
import pkg.pkg1.pkg2.module2
import pkg.pkg1.pkg2.module2.Class
import pkg1
import pkg1.pkg2
import pkg1.pkg2.module2
from pkg import module2.Class
from pkg import module2
from pkg import module1
from pkg.pkg1.pkg2 import module2
from pkg.pkg1 import module1
from pkg import module0
from pkg.pkg1.pkg2.module2 import Class
from pkg.pkg1.module1 import Class
from pkg.module0 import Class
2.7.2.2.2. 脚本文件在 pkg.pkg1 目录
from . import module0
from .. import module0
from .module0 import Class
import pkg.module0.Class
import pkg.module0
import module0
from pkg.module0 import Class
from pkg import module0
from module0 import Class
from . import module1
from .. import module1
from ... import module1
from .module1 import Class
import .module1
import pkg.pkg1.module1.Class
import pkg.pkg1.module1
import pkg.pkg1
import pkg1.module1.Class
import pkg1.module1
import pkg1
from pkg.pkg1.module1 import Class
from pkg.pkg1 import module1
from pkg import pkg1.module1
import module2
import .module2
import ..module2
import ...module2
from . import module2
from .. import module2
from ... import module2
import pkg
import pkg.pkg1
import pkg.pkg1.pkg2
import pkg.pkg1.pkg2.module2
import pkg.pkg1.pkg2.module2.Class
import pkg1
import pkg1.pkg2
import pkg1.pkg2.module2
from pkg import module2.Class
from pkg import module2
from pkg import module1
from pkg.pkg1.pkg2 import module2
from pkg.pkg1 import module1
from pkg import module0
from pkg.pkg1.pkg2.module2 import Class
from pkg.pkg1.module1 import Class
from pkg.module0 import Class
2.7.2.2.3. 脚本文件在 pkg.pkg1.pkg2 目录
2.7.2.2.4. 总结
2.7.2.3. 查看 Python IDLE 的导入语句
(略)
3 总结
- import statement 并不像看起来那么人畜无害,自求多福吧!
- 我只能用设置 PYTHONPATH 变量和递进式 self-debugging 啦!
- 不推荐相对导入。
- 只要换了 IDLE,就要先查看 PYTHONPATH 变量里有没有脚本引用的 module 所在的路径,没有就用 sys.path.append() 添加。
- PyCharm 使用 Anaconda 的系统环境也很普遍了,但二者的 PYTHONPATH 变量仍然各自独立,需要各自添加。
- 添加 PYTHONPATH 变量推荐直达子包。
- 其实,善用 site-package 也许才是真正的王道,只是我还不熟悉的情况下,就发生了这么多事情**
4 系统环境
- win7-64bit
- Spyder 4.2.5 ( Python 3.7.10)
- PyCharm 2020.3
|