【python进阶】import机制

本文主要探讨了python的import机制,会涉及到名称空间,变量作用域,import语句和相关的模块,以及包的管理等内容。

名称空间与作用域

名称空间: 就是名称和对象的绑定关系

作用域: 就是这个名称在哪些地方可见

我们可以这样理解一下,名称空间是说明这个名称"存在吗?",作用域是说明这个名称"我可以看见它吗?"。

名称空间一般有两个或者三个,为什么这么说呢,有两个是一只存在的,就是内建名称空间和全局名称空间,还有一个是局部名称空间,这个是在执行的时候,如果涉及到函数调用,那么会产生这个名称空间,如果函数调用结束,那么这个名称空间消失,所以说有两个或者三个名称空间。

名称空间的加载顺序是:内建名称空间,然后是加载执行模块的全局名称空间,最后如果有函数调用,出现局部名称空间。

名称查找的顺序是,先查找局部名称空间,然后查找全局名称空间,最后查找内建名称空间,如果都没有找到,那么会抛出NameError的异常。这下就很好理解变量的覆盖了,为什么在函数里面如果有一个和外部同名的变量,使用的是这个函数内部的变量而不是外部的变量了,因为在查找局部名称空间的时候已经找到,那么就使用它,而不是在继续查找了。

locals和globals函数

首先它们两个都返回的是字典,key是名称,value是名称对应的值,顾名思义,locals函数返回当前调用者的局部名称空间,globals返回当前调用者的全局名称空间(也就是可以访问哪些全局的属性)。在全局名称空间下,它们返回的内容相同。

A = 1

def f(x):
    y = 1
    print(globals())
    print(locals())

f(2)

返回的是:

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000254BC468898>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'D:/pycharm_wk/ETL/test.py', '__cached__': None, 'A': 1, 'f': }
{'y': 1, 'x': 2}

可以看见locals返回了{'y': 1, 'x': 2},而globals返回了很大一部分内容

我们直接在全局名称空间下使用:

print(globals())
print(locals())

返回的内容是:

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000027CC0978898>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'D:/pycharm_wk/ETL/test.py', '__cached__': None}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000027CC0978898>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'D:/pycharm_wk/ETL/test.py', '__cached__': None}

其实是完全相同的内容了。

__name____main__

我们知道__name__指示的是名字,比如模块名,函数名,类名等,而__main__只有在模块被直接执行的时候,__name__就会等于__main__

import 和 load

模块在加载(load)的时候会被执行,也就是说所有处于模块顶层的代码都会被执行,导入(import)可以多次导入,但是模块只会被加载一次。

比如有三个py文件:

py1.py

print('py1')

py2.py

import py1

print('py2')

main.py

import py2
import py1

print('main')

当我们执行main.py的时候,打印结果是:

py1
py2
main
  1. 我们在main.py里面import py2,首先加载并且执行py2.py
  2. 但是py2.py又引入了import py1,所以加载并且执行py1.py,所以先打印了py1
  3. py1.py加载完成后,回到py2.py,打印py2,执行完成后回到了main.py
  4. 遇到了import py1,python判断py1已经被import,不会重复import,所以执行下面的打印main

总结:模块的顶层代码(简单理解,就是没有缩进的代码)在 import的时候会被执行,但是多次import只会执行一次。

zip方式的导入

python支持导入zip方式,python会把zip文件看成一个目录(也就是一个包),和正常的使用方式一样。

pyc文件

通过python -m py_compile dst.py可以把dst.py文件编译为对应的pyc文件,当我们在使用import第一次导入某一个模块的时候,其实python会先load,其实也就是执行了导入的模块,生成了pyc文件,导入的也是这个里面的内容,那么我们完全可以提供pyc文件,而不用提供py源文件,别人的引入也是有效的。

reload函数

python3已经没有reload内建函数。可以使用imp和import模块实现同样的功能,而且提供了更多有用的函数。

__import__函数

交叉引用

你可能感兴趣的:(【python进阶】import机制)