python import fromlist_Python import

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() 中。

引用说明:

转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值