(window.webpackJsonp=window.webpackJsonp||[]).push([[311],{637:function(t,s,a){"use strict";a.r(s);var n=a(10),r=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"模块"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#模块"}},[t._v("#")]),t._v(" 模块")]),t._v(" "),s("h2",{attrs:{id:"import"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#import"}},[t._v("#")]),t._v(" import")]),t._v(" "),s("ul",[s("li",[s("p",[t._v("一个 py 脚本文件，可以被 Python 解释器直接运行，也可以通过 import 语句导入其它脚本文件，此时该脚本文件称为一个模块（module）。")])]),t._v(" "),s("li",[s("p",[t._v("用关键字 "),s("code",[t._v("import")]),t._v(" 可以将某个模块，导入到当前脚本。")]),t._v(" "),s("ul",[s("li",[t._v("例："),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" sys      "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 导入一个名为 sys 的模块")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sys\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("module "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sys'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("built"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sys"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("platform    "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 调用 sys 模块的成员")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'linux'")]),t._v("\n")])])])])])]),t._v(" "),s("li",[s("p",[t._v("执行 "),s("code",[t._v("from xx import xx")]),t._v(" 语句，可以从某个模块，导入指定名称的成员（即导入某个标识符）。")]),t._v(" "),s("ul",[s("li",[t._v("例："),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sys "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" platform\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" platform\n"),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'linux'")]),t._v("\n")])])])]),t._v(" "),s("li",[t._v("这种语法的优点：\n"),s("ul",[s("li",[s("code",[t._v("platform")]),t._v(" 这样的标识符，比 "),s("code",[t._v("sys.platform")]),t._v(" 更短，写代码时更方便。")])])]),t._v(" "),s("li",[t._v("这种语法的缺点：\n"),s("ul",[s("li",[s("code",[t._v("platform")]),t._v(" 这样的标识符，没有前缀，可能与当前作用域的某个标识符重名。")]),t._v(" "),s("li",[t._v("代码的可读性差。当读者看到 "),s("code",[t._v("platform")]),t._v(" 这样的标识符时，不知道它是当前脚本定义的变量，还是通过 import 导入的。")])])]),t._v(" "),s("li",[t._v("可以同时导入多个成员，用逗号分隔："),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sys "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" platform"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" path\n")])])])]),t._v(" "),s("li",[t._v("可以用 "),s("code",[t._v("import *")]),t._v(" 导入全部成员。但这样不能看出具体导入了哪些成员，导致代码的可读性很差，建议不要这样做。"),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sys "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("\n")])])])])])]),t._v(" "),s("li",[s("p",[t._v("可以用关键字 "),s("code",[t._v("as")]),t._v(" 将导入的标识符重命名：")]),t._v(" "),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" sys "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" _sys\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" sys "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" path "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("as")]),t._v(" _path\n")])])])]),t._v(" "),s("li",[s("p",[t._v("一般将 import 语句写在 Python 脚本的开头，使得导入的标识符，可在全局作用域内访问。")]),t._v(" "),s("ul",[s("li",[t._v("也可以将 import 语句写在某个函数或方法内，使得执行该语句块时才会执行 import 语句，并且导入的模块只能在该局部作用域内被访问。")]),t._v(" "),s("li",[t._v("pyinstaller 在打包 Python 脚本时，会将局部导入的各个模块一起收集，即使该 import 语句位于不会被执行的 if 分支。")])])])]),t._v(" "),s("h3",{attrs:{id:"包"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#包"}},[t._v("#")]),t._v(" 包")]),t._v(" "),s("ul",[s("li",[s("p",[t._v("在一个文件目录中，如果存在一个名为 "),s("code",[t._v("__init__.py")]),t._v(" 的文件（内容可以为空），则 Python 解释器会将该目录识别为一个包（package）。")]),t._v(" "),s("ul",[s("li",[t._v("一个包，主要作用是充当一个命名空间。\n"),s("ul",[s("li",[t._v("一个包，可以包含多个 Python 模块，作为该包的成员。")]),t._v(" "),s("li",[t._v("一个包，可以嵌套包含其它包目录。")])])]),t._v(" "),s("li",[t._v("用 "),s("code",[t._v("import")]),t._v(" 语句可以导入一个包，但本质上是导入包中的一个模块。\n"),s("ul",[s("li",[t._v("执行 "),s("code",[t._v("import <package>")]),t._v(" 语句，相当于执行 "),s("code",[t._v("import <package>.__init__")]),t._v(" ，导入包中一个名为 "),s("code",[t._v("__init__")]),t._v(" 的模块。")]),t._v(" "),s("li",[t._v("因此，每个包必须包含一个名为 "),s("code",[t._v("__init__.py")]),t._v(" 的文件。")])])])])]),t._v(" "),s("li",[s("p",[t._v("例：假设磁盘中存在以下文件目录")]),t._v(" "),s("div",{staticClass:"language-sh extra-class"},[s("pre",{pre:!0,attrs:{class:"language-sh"}},[s("code",[t._v("├── mypackage\n│   ├── __init__.py\n│   ├── module1.py\n│   └── module2.py\n└── test.py\n")])])]),s("p",[t._v("此时 mypackage 会被识别为一个包，可以在 test.py 文件中，执行以下几种 import 语句：")]),t._v(" "),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" mypackage\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" mypackage"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("module1\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v("   mypackage "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" module1\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v("   mypackage"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("module1 "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" xx\n")])])])])]),t._v(" "),s("h3",{attrs:{id:"寻址"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#寻址"}},[t._v("#")]),t._v(" 寻址")]),t._v(" "),s("ul",[s("li",[s("p",[t._v("执行 "),s("code",[t._v("import xx")]),t._v(" 可以导入某个模块或包，但 Python 解释器如何知道这个模块或包，的实际文件路径？")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("sys.path")]),t._v(" 的取值为 list 类型，记录了几个常用的目录。Python 解释器会到这些目录及其子目录中，查找名为 xx 的模块或包。")]),t._v(" "),s("li",[t._v("如果找到了，则导入。如果没找到，则抛出异常： "),s("code",[t._v("ModuleNotFoundError: No module named 'xx'")])]),t._v(" "),s("li",[t._v("例："),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sys"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("path\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("''")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'/usr/lib64/python39.zip'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'/usr/lib64/python3.9'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])])]),t._v(" "),s("li",[t._v("用户可以添加其它目录到 sys.path 中："),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" sys"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("path"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("append"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'/tmp'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),t._v("不过每次重启 Python 解释器时，都会重置 sys.path 的值，除非声明终端环境变量 "),s("code",[t._v("export PYTHONPATH=/tmp")])])])]),t._v(" "),s("li",[s("p",[t._v("如果一个脚本位于一个包内，则可以通过相对地址导入其它模块或包：")]),t._v(" "),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("utils "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("    "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 从当前目录导入（需要当前目录是一个包）")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v("        "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 从上层目录导入（需要当前目录、上层目录都是包）")]),t._v("\n")])])]),s("ul",[s("li",[t._v("如果该脚本被间接执行，则 Python 解释器会自动将这些相对地址，转换成绝对地址。")]),t._v(" "),s("li",[t._v("如果该脚本被直接执行，则 Python 解释器不能处理相对地址，会报错。")])])]),t._v(" "),s("li",[s("p",[t._v("如果模块名、包名会变化，如何导入？可以调用 importlib 模块的 import_module() 函数，输入一个 str 字符串作为模块名或包名，然后导入。")]),t._v(" "),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" importlib "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" import_module\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" m "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" import_module"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'os'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("                   "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 相当于 import os")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" m\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("module "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'os'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'/usr/lib64/python3.6/os.py'")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" m "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" import_module"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'os.path'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("              "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 相当于 import os.path")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" m\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("module "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'posixpath'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'/usr/lib64/python3.6/posixpath.py'")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" m "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" import_module"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sys'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" package"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'os'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("    "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 相当于 from os import sys")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" m\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("module "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'sys'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("built"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n")])])])])]),t._v(" "),s("h3",{attrs:{id:"间接执行"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#间接执行"}},[t._v("#")]),t._v(" 间接执行")]),t._v(" "),s("ul",[s("li",[s("p",[t._v("通过 import 导入一个模块时，实际上会执行一遍该模块的全部 Python 代码，然后将其中创建的所有对象，保存到当前脚本的作用域，供当前脚本访问。")]),t._v(" "),s("ul",[s("li",[t._v("例如：用 Python 解释器执行 a.py ，而 a.py 导入了 b.py ，则最终两个脚本都会被执行一次，只不过一个是被直接执行，一个是被间接执行。")]),t._v(" "),s("li",[t._v("例如，编写一个 test.py ："),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Hello'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("fun1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n    "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fun1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("fun2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n    "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fun2'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n    fun1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]),t._v(" "),s("li",[t._v("然后在终端导入该脚本："),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" test "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" fun2\nHello                       "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 这里间接执行了 print('Hello')")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" fun2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nfun2\nfun1                        "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 导入一个函数或类时，其调用的其它内容会被自动导入")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" fun1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("                  "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 但是并不能被直接访问，因为不存在于当前作用域")]),t._v("\nNameError"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" name "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'fun1'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("is")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("not")]),t._v(" defined\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" test "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" fun1   "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重复导入同一个模块，不会重复执行它。因此这里不会重复执行 print('Hello')")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" fun1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nfun1\n")])])]),s("ul",[s("li",[t._v("每个模块只会在第一次导入时，执行其中的 Python 代码。因此，如果修改了某个模块的内容，则需要重启 Python 解释器，才能重新导入该模块。")])])])])]),t._v(" "),s("li",[s("p",[t._v("Python 解释器导入一个模块时，会在该模块的同一目录下，生成一个 "),s("code",[t._v("__pycache__")]),t._v(" 文件夹，用于缓存该模块预编译生成的字节码文件（扩展名为 .pyc 或.pyo ）。")]),t._v(" "),s("ul",[s("li",[t._v("当 Python 解释器下一次导入该模块时，会检查该模块文件是否发生变化，没有的话就读取之前的 "),s("code",[t._v("__pycache__")]),t._v(" ，从而更快地导入。")]),t._v(" "),s("li",[s("code",[t._v("__pycache__")]),t._v(" 中会记录每个模块文件的修改日期，从而判断每个模块文件是否发生变化。")])])])]),t._v(" "),s("h3",{attrs:{id:"循环导入"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#循环导入"}},[t._v("#")]),t._v(" 循环导入")]),t._v(" "),s("ul",[s("li",[t._v("循环导入，是指两个 Python 模块相互导入，或者多个 Python 模块的导入关系形成一个回路。\n"),s("ul",[s("li",[t._v("这种操作是可行的，并不会引发报错。")]),t._v(" "),s("li",[t._v("此时相当于将多个模块中的所有 Python 语句，按导入顺序组合成一个大型脚本，可能产生冲突。")])])]),t._v(" "),s("li",[t._v("例：\n"),s("ol",[s("li",[t._v("创建两个循环导入的脚本文件："),s("br"),t._v("\nA.py ："),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'start'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" __name__"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" B\n"),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("B"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'end'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" __name__"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),t._v("B.py ："),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'start'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" __name__"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" A\n"),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("A"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'end'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" __name__"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]),t._v(" "),s("li",[t._v("执行时输出如下："),s("div",{staticClass:"language-sh extra-class"},[s("pre",{pre:!0,attrs:{class:"language-sh"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("root@CentOS ~"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# python3 A.py")]),t._v("\nstart __main__\nstart B\nstart A                               "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 此时 B.py 导入 A.py ，从头执行其中的代码，重复执行了 print('start', __name__)")]),t._v("\nTraceback "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("most recent call last"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(":\n  File "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"A.py"')]),t._v(", line "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("module"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("    "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 此时 A.py 尚未完成初始化，就导入 B.py ，输出 start B")]),t._v("\n    "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("import")]),t._v(" B\n  File "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"B.py"')]),t._v(", line "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("module"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("    "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 此时 B.py 尚未完成初始化，就导入 A.py ，输出 start A")]),t._v("\n    "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("import")]),t._v(" A\n  File "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"A.py"')]),t._v(", line "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("module"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("    "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 此时在 A.py 中访问 B.id ，但该变量尚未创建，所以报错")]),t._v("\n    print"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("B.id"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nAttributeError: partially initialized module "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'B'")]),t._v(" has no attribute "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("most likely due to a circular "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("import")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])])]),t._v(" "),s("li",[t._v("将 A.py 中的 "),s("code",[t._v("print(B.id)")]),t._v(" 改为 "),s("code",[t._v("print(dir(B))")]),t._v(" ，就可以循环导入。如下："),s("div",{staticClass:"language-sh extra-class"},[s("pre",{pre:!0,attrs:{class:"language-sh"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("root@CentOS ~"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# python3 A.py")]),t._v("\nstart __main__\nstart B\nstart A\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__builtins__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__cached__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__doc__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__file__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__loader__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__name__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__package__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__spec__'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\nend A             "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 此时 B.py 尚未完成初始化，但导入的 A.py 已经完整执行了一次，完成了初始化")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("                 "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 此时可以在 B.py 中访问 A.id")]),t._v("\nend B\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'A'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__builtins__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__cached__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__doc__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__file__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__loader__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__name__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__package__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'__spec__'")]),t._v(", "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'id'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\nend __main__\n")])])]),t._v("也可以将 A.py 中的 print(B.id) 放到不会立即执行的代码块中："),s("div",{staticClass:"language-py extra-class"},[s("pre",{pre:!0,attrs:{class:"language-py"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("test")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n    "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("B"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("id")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n")])])])])])])])])}),[],!1,null,null,null);s.default=r.exports}}]);