Python 的命名空间
admin
2023-07-31 00:38:43
0

懒得扫全文的童鞋,可以直接跳到最后看总结。
我们先从一个简单的栗子说起:

栗子

a 文件中有变量 va 以及类 A,b 文件导入 aclass A ,并打印出 A

123456789101112131415161718192021 #a.pyva = [\’dobi\’, \’a\’, \’dog\’] print(\’a1\’, id(va)) class A():    def __init__(self):        pass     def rtn(self):        global va        va.insert(1,\’is\’)        print(\’a3\’, id(va))        return va print(\’a2\’, va) #b.pyfrom a import A print(\’b\’, A)

执行 b 文件的结果为:

1234 Reloaded modules: aa1 2407907960200a2 [\’dobi\’, \’a\’, \’dog\’]b

可以发现,虽然 b 只是导入了 a 中的 class A,但导入这个过程却执行了整个 a 文件,那么我们是否能够在 b 中访问 a 中的全局变量 va 呢:

123456 print(va)# NameError: name \’va\’ is not definedprint(a.va)# NameError: name \’a\’ is not definedprint(b.va)# NameError: name \’b\’ is not defined

尝试了各类调用方法,发现都无法正常访问 a 的全局变量 va,既然 b 的导入执行了整个 a 文件,甚至还打印出了 vaid 和值,又为什么无法在 b 中调用 va 呢?

这个问题所涉及到的内容就是:命名空间。

但在开始正题之前,我们需要阐明若干概念:

一些基本概念的澄清

对象

Python 一切皆对象,每个对象都具有 一个ID、一个类型、一个值;对象一旦建立,ID 便不会改变,可以直观的认为 ID 就是对象在内存中的地址

123456789 a = [1, 2]b = aid(a)# 2407907978632id(b)# 2407907978632b[1] = 3a# [1, 3]

上例 a, b 共享了同一个 ID、同一个值、同一个类型。因此 a, b 表达的是同一个对象,但 a, b 又明显是不同的,比如一个叫 \'a\' 一个叫 \'b\'…既然是同一个对象,为什么又有不同的名字呢?难道名字不是对象的属性?

标识符

事实确实如此,这是 Python 比较特殊一点:如同\'a\' \'b\' 这样的名称其实有一个共同的名字:identifier(注意不要与 ID 混淆了),中文名为“标识符”,来解释一下:

标识符:各类对象的名称,比如函数名、方法名、类名,变量名、常量名等。

在 Python 中赋值并不会直接复制数据,而只是将名称绑定到对象,对象本身是不知道也不需要关心(该关心这个的是程序猿)自己叫什么名字的。一个对象甚至可以指向不同的标识符,上例中的\'a\' \'b\'便是如此。真正管理这些名子的事物就是本文的主角”命名空间” 。

命名空间

命名空间:(英语:Namespace)表示标识符(identifier)的可见范围。(ps:copy 自 SF)

简而言之,命名空间可以被简单的理解为:存放和使用对象名字的抽象空间

作用域

与命名空间相对的一个概念就是“作用域”,那么什么又是作用域呢?

作用域:(英文 Scope)是可以直接访问到命名空间的文本区域。

这里需要搞清楚什么是直接访问:

1234 #x.pya = 1class A():    def func():pass

1234 python x.pya   #直接访问# 1A.func  #属性访问

Python 中不加 . 的访问为直接访问,反之为属性访问。
因此作用域必定是相对某个对象内部而言的,比如一个函数内部、一个模块全局等,那作用域和命名空间是什么关系呢:

  1. 作用域是一种特殊的命名空间,该空间内的名称可以被直接访问;
  2. 并不是所有的命名空间都是作用域。

看不懂? 没关系,后面会解释,我们先回到命名空间这个话题上:

现今 Python 的大部分命名空间是通过字典来实现的,也即一个命名空间就是名字到对象的映射。另外, Python 允许对命名空间进行嵌套,而我们经常接触的命名空间有四层:

LEGB 规则

LEGB 层级

这四层命名空间可以简记为 LEGB:

  1. 局部命名空间(local):指的是一个函数所定义的空间或者一个类的所有属性所在的空间,但需注意的是函数的局部命名空间是一个作用域,而类的局部命名空间不是作用域。
  2. 闭包命名空间(enclosing function):闭包函数 的作用域(Python 3 引入)。
  3. 全局命名空间(global):读入一个模块(也即一个.py文档)后产生的作用域。
  4. 内建命名空间(builtin):Python 解释器启动时自动载入__built__模块后所形成的名字空间;诸如 str/list/dict…等内置对象的名称就处于这里。

为了说清楚这几层洋葱皮,举个栗子:

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...