代码改变世界

python 命名空间 重载模块

2022-04-05 16:59  jym蒟蒻  阅读(71)  评论(0编辑  收藏  举报

文章目录

    • 模块命名空间:
    • 重载模块:

 

#module2.py
print('starting to load...')
import sys
name=42
def func():pass
class klass:pass
print('done loading.')
>>> import module2
starting to load...
done loading.
>>> module2.sys
<module 'sys' (built-in)>
>>> module2.name
42
>>> module2.func
<function func at 0x000001FB71072E18>
>>> module2.klass
<class 'module2.klass'>
>>> dir(module2)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'func', 'klass', 'name', 'sys']


#moda.py:
X=88
def f():
    global X
    X=99
#modb.py:
X=11
import moda
moda.f()
print(X,moda.X)
#run modb.py:
>>> 
========================= RESTART: D:/python/modb.py =========================
11 99
#mod3.py:
X=3
#mod2.py:
X=2
import mod3
print(X,end=' ')
print(mod3.X)
#mod1.py:
X=1
import mod2
print(X,end=' ')
print(mod2.X,end=' ')
print(mod2.mod3.X)
#run mod1.py:
>>> 
========================= RESTART: D:/python/mod1.py =========================
2 3
1 2 3

#changer.py:
message='First version'
def printer():
	print(message)
        
>>> import changer
>>> changer.printer()
First version

#改变changer.py并保存:
message = 'After editing'
def printer():
    print('reloaded:',message)
#在解释器下面输入及其对应的输出:
>>> import changer
>>> changer.printer()
First version
>>> from imp import reload
>>> reload(changer)
<module 'changer' from 'D:/python\\changer.py'>
>>> changer.printer()
reloaded: After editing

模块命名空间:

0.作用域和命名空间:

作用域针对变量而言,是变量名被赋值的位置,决定变量名能被访问到的范围。

命名空间:变量名建立所在的场所。

注意模块不是模块对象,模块的变量名也不是模块对象的属性,但是你导入模块之后,就都是了,也就是说作用域还是命名空间他们是没有具体的分别的。

模块对象的属性在模块文件的作用域里面建立,所以我们说,模块对象的作用域也是命名空间。

1.模块是一个独立的作用域,导入后,模块文件的作用域就变成了模块对象属性的命名空间。简而言之,模块就是命名空间,存在于模块之内的变量名就是模块对象的属性。

2.模块对象:模块可以被理解成变量名的封装,导入一个模块文件之后,python会建立模块对象,包含模块文件内所赋值的所有变量名。

3.模块文件变为模块对象的过程:模块语句在首次导入时执行,python建立空的模块对象,然后按照文件从头到尾顺序依次执行该模块文件内部语句。文件顶层赋值变量的语句,会建立模块对象的属性,赋值的变量名会存储在模块的命名空间里。

4.由导入而建立的模块的命名空间是通过辞典对象进行存储的,命名空间只是普通的字典对象,可以通过dir(M)获取,它还包含了类继承的变量名。我们在模块文件中赋值的变量名,在内部成为字典的键。字典中多数变量名都反映了文件中顶层的赋值语句,python也会在模块命名空间里加一些变量名,_file_指明模块从哪个文件加载,_name_指明导入者名称。

5.在模块中,模块范围会在模块加载后变成模块对象的属性辞典,函数的本地变量名只在函数执行时存在,但是模块的本地作用域和全局作用域相同。因此我们说:导入后,模块文件的作用域就变成了模块对象的属性的命名空间。

6.我来总结一下:导入一个模块,建立一个空的模块对象,然后执行模块中语句,如果有赋值变量的语句,那么就建立模块对象的属性,这个被赋值的变量名会被存到字典(命名空间)里,模块加载完之后,这个模块的作用域就是模块对象属性的命名空间,我们可以通过模块名和变量名(键/模块对象)获取命名空间里的属性(值)。

7.看中文也看不太明白,估计是翻译的锅,里面好多地方自相矛盾,我现在也没完全理解。到时候买个英文看看再过来修改吧。

1.点号运算符:object.attribute利用点号运算符获取任意对象object的attribute属性。点号运算是表达式,返回和对象相匹配的属性名的值。用点号运算符读取变量名时(属性),已经把对象给明确了。

如果只有一个简单变量,那么在当前作用域内找变量名x(遵循LEGB,无点号运算的纯变量名)

X.Y:当前范围内搜索X,然后搜索对象X中的属性Y。

X.Y.Z:寻找对象X中的变量Y,然后再找对象X.Y中的Z

点运算可用于任何具有属性的对象,比如模块,类

2.导入和作用域:

不导入文件,就无法存取该文件内定义的变量名。

在例子里,第二个模块modb定义了全局变量x,导入第一个模块,调用了第一个模块的函数。第一个模块的函数修改moda模块里的全局变量x,而不是modb中的x

我们可以看出,导入操作不会赋予被导入文件中(moda)代码对上层代码(modb)的可见度。函数无法看见其他函数内的变量名,除非它处于这个函数内。模块代码无法看见其他模块内的变量名,除非你把它导入到这个其他模块里。

3.命名空间的嵌套:

导入不会使命名空间发生向上的嵌套,但是会发生向下的嵌套。有可能深入到任意嵌套的模块中并读取其属性。

这里我们的例子:mod1导入mod2时,创建一个两层命名空间的嵌套,利用mod2.mod3.X就可以深入到mod3。也就是说,mod1可以访问三个文件的全局范围。

但是反过来则不可以,mod3无法看见mod2和mod1的变量名

import语句:将整个模块对象赋值给一个变量名

在mod1中,mod2只是一个 变量名,引用带有属性的对象,而该对象某些属性可能又引用其他带有属性的对象。我们可以说,mod1 import mod2 然后mod2.mod3.X

我们不能说import mod2.mod3。因为这个语句涉及包导入,包导入也会形成模块命名空间嵌套。其导入语句会反映目录树结构,而不是简单的导入链。

重载模块:

模块程序代码默认只对每个过程执行一次,强制使模块代码重新载入并运行,需要调用reload,在python3中,reload为于模块中,使用前需要导入。

只会在第一次导入模块时,加载和运行该模块的代码,之后的导入只会使用已经加载的模块对象,而不会重载或重新执行文件的代码。

reload会强制将已经加载的模块代码重新载入并重新执行,模块新代码的赋值语句会修改现有的模块对象。

利用reload可以立即看到对组件修改的效果。一般用法就像例子里的,导入一个模块,然后修改其代码,然后将其重载。调用reload时,python重新读取模块的源代码,然后执行顶层语句。reload会重新在当前命名空间内执行模块文件的新代码并且覆盖其现有的命名空间,而不会删除然后重建模块对象。

重载之后,模块对象的某些变量的值变成了新的值,因此会影响所有使用import读取了模块对象的客户端。

之前使用from读取属性的客户端不会受到影响,但是之后使用from的会受到影响。

重载的好处:

使程序提供高度动态的接口,用户可以在系统运作时编写python程序,而不用获取整个源代码,然后编译整个产品。而且对于那些启动时需要连接服务器的程序来说,利用重载就好太多了,因为我们虽然改动代码,但不用再重新启动。python真的动态,我喜欢!