python中导入模块有哪些_Python基础38-包/模块(导入及其底层逻辑)

1 导入模块后具体做了什么?

2 从哪个位置找到需要导入的模块

3 导入模块的常见场景?

1 导入模块后具体做了什么?

1.1 第一次导入

在自己当下的命名空间中,执行所有代码

创建一个模块对象,并将模块内所有顶级变量以属性的形式绑定在模块对象上

在 import 的位置,引入 import 后面的变量名称到当前命名空间

1.1.1 在自己当下的命名空间中,执行所有代码

Test2.py

name = "Test2"

age = 2

print("执行了Test2所有代码")

Test1.py

import Test2

# 让后 run 该分代码

>>>>打印结果

执行了Test2所有代码

也就是说 Test1.py 中导入了 Test2模块后,在运行 Test1模块代码时,会先让 Test2中的代码在 Test2 的自己的命名空间中执行 Test2的所有代码

其实,从使用角度来理解的话,当然是 Test2 内的代码先跑完,Test1 中才能使用 Test2 中的变量等资源啊。

1.1.2 创建一个模块对象,并将模块内所有顶级变量以属性的形式绑定在模块对象上

(具有内存地址及类型)

Test2.py

name = "Test2"

age = 2

print("执行了Test2所有代码")

Test1.py

import Test2

# 查看Test2

print(Test2)

# 查看内存地址

print(id(Test2))

# 查看类型

print(type(Test2))

# 通过打印 Test2 对象的属性,验证在 Test1 中需要通过 模块名.属性形式访问的原因

print(Test2.__dict__)

>>>>打印结果

执行了Test2所有代码

4560942648

# __dict__ 字典打印结果没有天上自己试验

1.1.3 在 import 的位置,引入 import 后面的变量名称到当前命名空间

在 Test1 中通过 Test2变量名来使用 Test2 模块的资源

Test2.py

name = "Test2"

age = 2

print("执行了Test2所有代码")

Test1.py

import Test2

print(Test2.name)

print(Test2.age)

>>>>打印结果

执行了Test2所有代码

Test2

2

将 Test2 这个指向 Test2 模块的对象变量名引入 当前 命名空间中(注意命名空间即作用域的区别)

Test1.py

def testFunc():

import Test2 # 导入到了函数的命名空间中

print(Test2.name)

testFunc()

print(Test2.name) # 全局命名空间不能使用 Test2

>>>>打印结果

Traceback (most recent call last):

执行了Test2所有代码

File "/Users/xxx/Desktop/PythonProject/PackageAndModule/Test1.py", line 14, in

Test2

print(Test2.name)

NameError: name 'Test2' is not defined

1.2 第二次导入

1.2.1直接执行1.1.3这个步骤

Test2.py

name = "Test2"

age = 2

print("执行了Test2所有代码")

Test1.py

import Test2

print(Test2.name)

print(Test2.age)

# 再次导入, 打印中并没有出现两次“执行了Test2所有代码”

import Test2

>>>>打印结果

执行了Test2所有代码

Test2

2

1.3 注意

from ... import ... 导入方式与 import ... 导入方式底层执行步骤区别

两种导入方式均都会大致的执行上述的3个步骤

多次导入模块,该模块并不会执行多次

两种导入方式并不存在哪一种更节省内存之说,区别在于把哪一部分内容拿到当前位置来用,因为一旦导入都将模块内的对象创建好。

Test2.py

name = "Test2"

age = 2

print("执行了Test2所有代码")

Test1.py

from Test2 import name

print(name)

>>>>打印结果

执行了Test2所有代码

Test2

2 模块检索顺序(从哪个位置找到需要导入的模块)

2.1 第一次导入

按照模块检索路径顺序查找

1 内建模块

2 sys.path

2.1 当前目录环境变量PYTHONPATH

2.2 Python 安装路径

2.3 安装路径下的.pth 路径

2.4 lib 库 site-packages

2.5 lib 库 site-packages下的 pth 文件配置

3 其他

2.2.1 第一层级

内置模块

2.2.2 第二层级

sys.path

>>> import sys

>>> print(sys.path)

['', '/usr/local/Cellar/python3/3.6.4_1/Frameworks/Python.framework/Versions/3.6/lib/python36.zip', '/usr/local/Cellar/python3/3.6.4_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6', '/usr/local/Cellar/python3/3.6.4_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/site-packages']

>>>

构成 (如下索引并非指优先顺序)

1.1 当前目录

1.2 环境变量 PYTHONPATH 中指定的路径列表

1.3 特定路径下的 .path 文件中的文件路径列表

1.4 在 Python 安装路径的 lib 库中搜索

追加路径的方式(修改 sys.path 方式)

直接修改 sys.path,只作于本次的执行代码模块

6a99e5e4c1b5?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

Test1.py

import sys

sys.path.append("/Users/xxx/Desktop/myTest")

print(sys.path)

import fkm

# print(fkm.__dict__)

print(fkm.age)

>>>>打印结果

打印了abc 所有代码

12

注意该路径是追加到sys.path最后的,当 工程目录中有同名模块时,会优先加载工程内的同名模块

修改环境变量 PYTHONPATH(自行百度)

实际,修改PYTHONPATH环境变量也是修改 sys.path 列表内容,将环境变量PYTHONPATH代表的路径添加到 sys.path中,只不过是默认就给添加了,不同于通过代码修改。

注意,系统修改 PYTHONPATH 和 pycharm 添加环境变量的区别

添加.pth 文件

添加 .pth 文件位置可通过 site 模块查看

import site

print(site.getsitepackages())

>>>>打印结果

['/usr/local/Cellar/python3/3.6.4_1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages', '/Library/Python/3.6/site-packages']

只需在以上目录下创建.pth 文件,然后在文件中添加对应模块路径即可

2.2 第二次导入

1 从已经加载过的模块中去找

查看已加载模块

import sys

sys.modules

3 导入模块的常见场景?

3.1 局部导入

def testFunc():

import Test2 # 导入到了函数的命名空间中

print(Test2.name)

testFunc()

使用的时候才进行导入,此时 Test2 是一个局部变量,只存在于函数作用域中;减少内存的开销;

3.2 覆盖导入

场景一:

自定义模块和非内置的标准模块重名,根据前者的存储位置,有可能前者会覆盖后者

建议:自定义模块命名不要与后者重名

场景二:

自定义模块与内置模块重名,内置肯定覆盖自定义

建议:如果确实需要使用重名的自定义模块,可以使用 from ... import ...方式指明绝对路径进行导入使用

from package1 import sys

print(sys.name)

3.3 循环导入

模块 A 中导入模块 B, 模块 B 中又导入模块 A;

Test2.py

t2_1 = "t2_1"

t2_2 = "t2_2"

import Test1

print(Test1.t1_1)

print(Test1.t1_2)

Test1.py

t1_1 = "t1_1"

t1_2 = "t1_2"

import Test2

print(Test2.t2_1)

print(Test2.t2_2)

>>>>打印结果

t2_1

t2_2

t1_1

t1_2

t2_1

t2_2

6a99e5e4c1b5?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

分析逻辑

3.4 可选导入

两个功能相近的包,根据需求优先选择其中一个导入

想优先使用 A;当没有 A 的情况下,使用 B 作备份

try:

import Testxxx as t

except ModuleNotFoundError:

import Test1 as t

print(t.name)

3.5 包内导入

6a99e5e4c1b5?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

明确一下概念

绝对导入和相对导入,这两个概念是相对于包内导入而言的

包内导入:即是包内的模块导入包内的模块,即package1包内的 Test3 内导入 Test3_1

包外导入:即是包外的模块导入包内的模块,即 Test1 内导入package1包内的 Test3

查看当前文件参照的执行路径

import sys

sys.path

查看当前模块名称

如果文件是直接运行的话,__name__的值是 __main__

如果是以模块的形式进行加载文件的话,该名称的值则是由加载路径决定,格式为:包名.子包名.模块名 (此时,第一层包名称作为顶级名称)

print(__name__)

Test1.py

import package1.Test3

Test3

查找文件顺序都是先 内置 再 sys.path

当点击运行(使用解析器去执行)某一 py 文件时,此时程序会确定当前py 文件所在的目录,并且将该目录添加到 sys.path 中,此时的 sys.path内容基本确定

3.5.1 概念

3.5.1.1 绝对

参照sys.path路径进行检索

指明包名或模块名import a、from a import b

上述两点是基于 Python3.x 之后

3.5.1.2 相对

使用.来指代相对路径

.:根据模块名(__name__)称所获取的当前目录

..:根据模块名(__name__)称所获取的上层目录

如:from . import a、from .. import a

3.5.2 补充

Python3.x 版本之前,直接使用 import a。会优先从本地当前目录查找,并非是 sys.path

解决方案:from __future__ import absolute_import,使用该代码语句改变 import 行为

3.5.3 结论

包内导入,使用相对导入

包外导入,使用绝对导入

例子1:Test1 导入 Test3,Test3 内又导入Test3_1;即包外导入+包内导入

Test1.py

import package1.Test3

from package1 import Test3

Test3.py

from . import Test3_1

不建议写成 from package1 import Test3_1 ,因为当包名变化时,使用包名的地方都要改动

例子2:多层级导入

6a99e5e4c1b5?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

Test1.py

print("Test1")

print(__name__)

from package1 import Test3

Test2.py

print("Test2")

print(__name__)

Test3.py

print("Test3")

print(__name__)

from .package_sub1 import Test4

Test3_1.py

print("Test3_1")

print(__name__)

Test4.py

print("Test4")

print(__name__)

from .package_subsub1 import Test5

Test4_1.py

print("Test4_1")

print(__name__)

Test5.py

print("Test5")

print(__name__)

from .. import Test4_1

from ... import Test3_1

# from .... import Test2 #包内不能获取包外的文件

运行 Test1.py

>>>>打印结果

Test1

__main__

Test3

package1.Test3

Test4

package1.package_sub1.Test4

Test5

package1.package_sub1.package_subsub1.Test5

Test4_1

package1.package_sub1.Test4_1

Test3_1

package1.Test3_1

可以通过上述例子,了解点点的作用

注意:包内不能获取包外的文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值