1.分类:
(1)局部命名空间:每个函数都有自已的局部命名空间,它记录了函数的变量,包括函数的参数和局部定义的变量。
(2)全局命名空间:每个模块都有自已的全局命名空间,它记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
(3)内置命名空间:任何模块均可访问它,它存放着内置的函数和异常。
2.查找顺序:局部命名空间(嵌套函数先到自己的命名空间搜索,再到父函数的命名空间搜索) ==> 全局命名空间 ==> 内置命名空间,如果均没有查找到,将引发一个 NameError 异常。
3.生命周期:局部命名空间在函数被调用时创建,当函数返回或抛出异常时被删除。全局命名空间在模块定义被读入时创建,一直保存到解释器退出。内置命名空间在 Python 解释器启动时创建,一直保留。
4.局部命名空间:
可以通过内置函数 locals() 查看。locals() 返回局部命名空间的一个拷贝,修改它对局部命名空间没有影响。
#代码
deffoo():
a= 1
print("locals: %s" %locals())
foo()#结果
locals: {'a': 1}
5.全局命名空间:
可以通过内置函数 globals() 查看。globals() 返回真实的全局名字空间,修改它会影响全局命名空间。
#代码
importcopyfrom copy importdeepcopy
a= 1
deffoo():
b= 2
print("globals: %s" %locals())
foo()#结果
globals: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'copy': , 'deepcopy': , 'a': 1, 'foo': }
import module:模块自身被导入,保持自已的命名空间,访问时需要用 module.function ;
from module import function:从另一个模块中将指定的函数和属性导入到自己的命名空间,访问时可以直接用 function 。
内置命名实际上存在于一个叫 __builtins__ 的模块中,可以通过 globals()['__builtins__'].__dict__ 查看其中的内置函数和内置异常。
#代码
print("builtins: %s" % globals()['__builtins__'].__dict__)#结果
builtins: {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': , '__spec__': ModuleSpec(name='builtins', loader=), '__build_class__': , '__import__': , 'abs': ,...
二、导入方式
python 导入部分的代码在 Lib/importlib 包中,官方文档。
python 的导入依靠 __import__() 函数实现,其他导入方式中 import 语句是 __import__() 函数的语法糖,import_module() 函数是一个对 __import__() 进行简化的包装器。
三者区别如下:
1.import:先带有适当的参数调用 __import__() 函数,然后将返回值绑定到当前作用域中的命名空间里。
2.__import__():执行模块搜索以及在找到时的模块创建操作,返回最高层级的包或模块(如 pkg )。
3.import_module():对 __import__() 进行简化的包装器,返回指定的包或模块(如 pkg.mod )。
python 导入的都是模块对象类型( module ),模块有一种特殊类型包( package ), 任何具有 __path__ 属性的模块都会被当作是包。包有两种类型,常规包和命名空间包。
常规包通常以一个包含 __init__.py 文件的目录形式实现。(不带__init__.py 文件的目录不会被python识别为包)
第一次导入包时会执行一遍 __init__.py 文件,第一次导入模块时会执行一遍模块文件。
首次导入一个模块时,Python 会按顺序搜索该模块,如果找到就创建一个 module 对象并初始化它; 如果未找到则会引发 ModuleNotFoundError 。
搜索的顺序是: sys.modules ==> sys.path[0] (当前目录) ==> sys.path[1:]
sys.modules:执行 py 文件时,首先会默认加载一些模块( sys.builtin_module_names 列出的内置模块,标准库)并存放在 sys.modules 中;之后 import 载入的模块也会存放在 sys.modules 中。
sys.path[0]:执行 py 文件时会把文件所在的 directory 存入 sys.path[0] 中。直接执行存入的是绝对路径,带 -m 参数执行存入的是相对路径,交互式执行环境存入的是相对路径。
sys.path[1:] :第三方模块默认安装位置在环境变量 site-packages 中。
直接执行时 sys.path[0] 存入的是绝对路径,__name__ = '__main__' ,此时如果使用相对导入会报错;带 -m 参数执行时 sys.path[0] 存入的是相对路径,__name__ = 'package.subpackage.module' ,此时可以使用相对导入。
#test.py
importsysprint(sys.path)#直接执行 (作为 top-level 脚本,__name__ = '__main__')
python test.py
['C:\\test.py', 'D:\\SoftwareIT\\Python\\python37.zip', 'D:\\SoftwareIT\\Python\\DLLs', 'D:\\SoftwareIT\\Python\\lib', 'D:\\SoftwareIT\\Python', 'D:\\SoftwareIT\\Python\\lib\\site-packages']#带-m参数执行 (作为 module,同import,__name__ = 'package.subpackage.module')
python -m test
['', 'D:\\SoftwareIT\\Python\\python37.zip', 'D:\\SoftwareIT\\Python\\DLLs', 'D:\\SoftwareIT\\Python\\lib', 'D:\\SoftwareIT\\Python', 'D:\\SoftwareIT\\Python\\lib\\site-packages']#交互式执行环境
>>> importsys>>> print(sys.path)
['', 'D:\\SoftwareIT\\Python\\python37.zip', 'D:\\SoftwareIT\\Python\\DLLs', 'D:\\SoftwareIT\\Python\\lib', 'D:\\SoftwareIT\\Python', 'D:\\SoftwareIT\\Python\\lib\\site-packages']
如下图,import os 时,在 sys.modules 中找到了 os 模块,停止搜索;不会继续在 sys.path[0] 中搜索同目录下的 os.py 文件,因此 os.getcwd() 没有报错。
from redis import Redis 时,在 sys.modules 中没有找到 redis 模块,继续搜索;按 sys.path[0] 的路径搜索到同目录下的 redis.py 文件,redis.py 文件没有 Redis 方法,因此报错。此时第三方库 redis 的路径 site-packages 在 sys.path[1:] 中,还没有执行搜索。
#目录结构
├── __init__.py
├── os.py
├── redis.py
└── test.py#代码 test.py
importos
os.getcwd()from redis importRedis#结果 python test.py
Traceback (most recent call last):
File"test.py", line 3, in
from redis importRedis
ImportError: No module named redis
四、import
1.import A:
查找一个模块,如果有必要还会加载并初始化模块;
如果未找到该模块,则引发 ModuleNotFoundError ;
在局部命名空间中为 import 语句发生位置所处的作用域定义一个或多个名称,如果有 as 子句则使用其指定的名称,否则使用该属性的名称。
2.from A import B:
查找 from 子句中指定的模块,如有必要还会加载并初始化模块;
如果未找到该模块,则引发 ModuleNotFoundError ;
对于 import 子句中指定的每个标识符:检查被导入模块是否有该名称的属性,如果没有,尝试导入具有该名称的子模块,然后再次检查被导入模块是否有该属性;
如果未找到该属性,则引发 ImportError ;
否则的话,将对该值的引用存入局部命名空间,如果有 as 子句则使用其指定的名称,否则使用该属性的名称。
3.from A import *(不推荐使用):
仅在模块层级上被允许,如果在类或函数定义中使用它将引发 SyntaxError 。
在模块中定义的全部公有名称都将被绑定到局部命名空间。
模块的公有名称由模块命名空间中的 __all__ 的变量确定(包则由 __init__.py 文件的 __all__ 的变量确定), __all__ 是一个字符串列表 __all__ 。如果 __all__ 没有被定义,则公有名称是模块命名空间中所有不以 '_' 开头的名称。
(1)绝对导入:
import A.B ,from A import B 这种形式的 import 为绝对导入。
(2)相对导入:
from .A import B 这种形式的 import 为相对导入。
相对导入仅在包内导入时有效,包通常指包含 __init__.py 文件的目录。如 A 目录下没有 __init__.py 文件,则不可以使用相对导入。
一个前缀点号表示相对导入从当前包开始。 两个或更多前缀点号表示对当前包的上级包的相对导入,第一个点号之后的每个点号代表一级。
五、__import__()
1.定义:
内置函数,不用 import,在库中位置:importlib.__import__() 。
__import__(name, globals=None, locals=None, fromlist=(), level=0)
2.参数:
name 参数指定了导入的模块名。
globals 和 locals 参数确定了语句的上下文。
fromlist 参数给出了应该从由 name 参数指定的模块导入对象或子模块的名称。
level 参数指定了是使用绝对还是相对导入。0(默认值)表示绝对导入,正数表示相对导入,数值大小即为父目录层数。
#import 语句与等价的 __import__() 语句
importspam
spam= __import__('spam', globals(), locals(), [], 0)importspam.ham
spam= __import__('spam.ham', globals(), locals(), [], 0)from spam.ham importeggs, sausage as saus
_temp= __import__('spam.ham', globals(), locals(), ['eggs', 'sausage'], 0)
eggs=_temp.eggs
saus= _temp.sausage
当 name 变量的形式为 pkg.mod 时,通常将会返回最高层级的包(第一个点号之前的名称),而不是以 name 命名的模块。 但是当给出了非空的 fromlist 参数时,则将返回以 name 命名的模块。
正常情况下一般不直接使用 __import__() 函数。
六、import_module()
1.定义:
非内置函数,需要 import,在库中位置:importlib.import_module() 。
importimportlib
importlib.import_module(name, package=None)
2.参数:
name 参数指定了以绝对或相对导入方式导入什么模块(如 pkg.mod 或 ..mod )。
package 参数为包名。如果 name 参数为相对导入方式,则 package 参数不能为空(如 import_module('..mod', 'pkg.subpkg') 将会导入 pkg.mod )。
import_module() 返回指定的包或模块(如 pkg.mod )。
import_module() 函数可以用于动态导入模块。
七、常见陷阱
问题:模块A引用了模块B,模块B同时也引用了模块A。
#A.py
from .B importB_greet_backdefA_say_hello():print('A says hello!')
B_greet_back()defA_greet_back():print('A says hello back!')if __name__ == '__main__':
A_say_hello()#B.py
from .A importA_greet_backdefB_say_hello():print('B says hello!')
A_greet_back()defB_greet_back():print('B says hello back!')if __name__ == '__main__':
B_say_hello()#运行
python -m sample_package.B#结果
ImportError: cannot import name 'A_greet_back'
如上图,sample_package 包里有 A 和 B 两个模块,当 B 执行时,会导入 A_greet_back ,导入时自动执行一遍 A ,而当 A 执行时,会导入 B_greet_back ,这样就出现了死循环。
解决方法:
(1)导入整个模块:将 from .A import A_greet_back 更改为 from . import A,这样就不会在 A 模块中去找 A_greet_back 的定义了,只需要确认 A 模块是否存在。
(2)延迟导入:将 from .A import A_greet_back 放入 B_say_hello() 中。
引用说明:
转载请注明出处。