编程派微信号:codingpy

前言python里面最核心的内容就是:名字空间(namespace)

例子引入

例1

可以正常输出结果: 并且需要注意,在func2使用x变量之前的名字空间就已经有了'x':1.

稍微改一点:如下

例2:

输出就开始报错: 而且在before func2也没有了x.

这两个例子正好涉及到了python里面最核心的内容:名字空间,正好总结一下,然后在解释这几个例子。

名字空间(Namespace)

比如我们定义一个”变量”

所以,这里更准确的叫法应该是名字。 一些语言中比如c,c++,java 变量名是内存地址别名, 而Python的名字就是一个字符串,它与所指向的目标对象关联构成名字空间里面的一个键值对{name: object},因此可以这么说,python的名字空间就是一个字典。

分类

python里面有很多名字空间,每个地方都有自己的名字空间,互不干扰,不同空间中的两个相同名字的变量之间没有任何联系一般有4种: LEGB四种locals:函数内部的名字空间,一般包括函数的局部变量以及形式参数

enclosing function:在嵌套函数中外部函数的名字空间, 对fun2来说, fun1的名字空间就是.

globals:当前的模块空间,模块就是一些py文件。也就是说,globals()类似全局变量。

__builtins__: 内置模块空间,也就是内置变量或者内置函数的名字空间。

当程序引用某个变量的名字时,就会从当前名字空间开始搜索。搜索顺序规则便是: LEGB。

一层一层的查找,找到了之后,便停止搜索,如果最后没有找到,则抛出在NameError的异常。这里暂时先不讨论赋值操作。

比如例1中的a = x +1 这行代码,需要引用x,则按照LEGB的顺序查找,locals()也就是func2的名字空间没有,进而开始E,也就是func1,里面有,找到了,停止搜索,还有后续工作,就是把x也加到自己的名字空间,这也是为什么fun2的名字空间里面也有x的原因。

访问方式

其实上面都已经说了,这里暂时简单列一下 1. 使用locals()访问局部命名空间 2. 使用globals()访问全局命名空间。

这里有一点需要注意,就是涉及到了from A import B 和import A的一点区别。

输出结果:

从输出结果可以看出globals()包含了定义的函数,变量等。对于'deepcopy': 可以看出deepcopy已经被导入到自己的名字空间了,而不是在copy里面。 而导入的import copy则还保留着自身的名字空间。

因此要访问copy的方法,就需要使用copy.function了。这也就是为什么推荐使用import module的原因,因为from A import B这样会把B引入自身的名字空间,容易发生覆盖或者说污染。

生存周期

每个名字空间都有自己的生存周期,如下:__builtins__: 在python解释器启动的时候,便已经创建,直到退出

globals:在模块定义被读入时创建,通常也一直保存到解释器退出。

locals : 在函数调用时创建,直到函数返回,或者抛出异常之后,销毁。 另外递归函数每一次均有自己的名字空间。

看着没有问题,但是有很多地方需要考虑。比如名字空间都是在代码编译时期确定的,而不是执行期间。这个也就可以解释为什么在例1中,before func2:的locals()里面包含了x: 1 这一项。再看下面这个

肯定会报错的,但是错误不是

而是:

虽然x = 10永远不会执行,但是在执行之前的编译阶段,就会把x作为locals变量,但是后面编译到print的时候,发现没有赋值,因此直接抛出异常,locals()里面便不会有x。这个就跟例子2中,before func2里面没有x是一个道理。

赋值

为什么要把赋值单独列出来呢,因为赋值操作对名字空间的影响很大,而且很多地方需要注意。 核心就是: 赋值修改的是命名空间,而不是对象, 比如:

这个语句就是把a放入到了对应的命名空间, 然后让它指向一个值为10的整数对象。

这个就是把a放入到名字空间,然后指向一个列表对象, 然而后面的a.append(1)这句话只是修改了list的内容,并没有修改它的内存地址。因此并没有涉及到修改名字空间。

赋值操作有个特点就是:赋值操作总是在最里层的作用域,也就说,只要编译到了有赋值操作,就会在当前名字空间内新创建一个名字,然后开始才绑定对象。即便该名字已存在于赋值语句发生的上一层作用域中;

总结

分析例子

现在再看例子2, 就清晰多了, x += x 编译到这里时,发现了赋值语句,于是准备把x新加入最内层名字空间也就是func2中,即使上层函数已经存在了; 但是赋值的时候,又要用到x的值,然后就会报错:

这样看起来好像就是 内部函数只可以读取外部函数的变量,而不能做修改,其实本质还是因为赋值涉及到了新建locals()的名字。 在稍微改一点:

这个结果就是:

咋正确了呢—这不应该要报错吗?

其实不然,就跟上面的a.append(1)是一个道理。 x[0] += x[0]这个并不是对x的赋值操作。按照LEGB原则, 搜到func1有变量x并且是个list, 然后将其加入到自己的locals(),后面的x[0] += x[0], 就开始读取x的元素,并没有影响func2的名字空间。

另外无论func1与func2的名字空间的x没有什么关系,只不过都是对[1, 2]这个列表对象的一个引用。

这个例子其实也给了我们一个启发,我们知道内部函数无法直接修改外部函数的变量值,如例2,如果借助list的话,就可以了吧!比如把想要修改的变量塞到一个list里面,然后在内部函数里面做改变!当然python3.x里面有了nonlocal关键字,直接声明一下就可以修改了。看到这里,对作用域理解应该有一点点了吧。

延伸

与闭包的不同

我们都知道闭包是把外部函数的值放到func.func_closure里面,为什么不像上面的例子一样直接放到函数的名字空间呢?这是因为locals()空间是在函数调用的时候才创建! 而闭包只是返回了一个函数, 并没有调用,也就没有所谓的空间。

locals()与globals()

在最外层的模块空间里locals()就是globals()

另外我们可以手动修改globals()来创建名字

但是locals()在函数里面的话, 貌似是不起作用的,如下:

这是因为解释器会将 locals 名字复制到 一个叫FAST的区域来优化访问速度,而实际上解释器访问对象时,是从FAST区域里面读取的,而非locals()。

所以直接修改locals()并不能影响x(可以使用exec动态访问,不再细述)。 不过赋值操作,会同时刷新locals()和FAST区域。

查了不少资料,说了这么多,我只想说,作为python最核心的东西,名字空间还有很多很多地方需要探究,比如作用域(scope)与名字空间,这里只是模糊了二者的区别

面向对象,也就是类的名字空间, 又有不一样的地方。。。

学一点记录一点吧。

扫码关注编程派

获取最新教程及资源推送

↓↓↓ 点击阅读原文,查看更多Python教程

阅读原文:http://mp.weixin.qq.com/s?__biz=MzAwNDc0MTUxMw==\x26mid=2649639698\x26idx=1\x26sn=c4559bb43b3e98626e9a2f1b65f8ca76\x26chksm=833dabf4b44a22e257a4a38d15f616ff1bd04ae776f83d583899bdeed426803cf091de1280ac#rd

python中space_漫谈Python的Namespace相关推荐

  1. python中什么是异常,python中异常处理,python异常处理,什么是异常?异常是一

    python中异常处理,python异常处理,什么是异常?异常是一 什么是异常? 异常是一个事件,该事件会在程序的执行中发生,影响程序的正常运行,一般情况下,在python无法正常处理程序时,就会发生 ...

  2. python中choicebox_学习python的第四天笔记

    26.032 异常处理 常用的异常警告语句: AssertionError:断言语句失败 AttributeError:访问的未知的对象属性,#例如f.dcp(),.dcp()是不存在的 IndexE ...

  3. python中if错误-Python中常见的异常处理

    异常和错误 part1:程序中难免出现错误,而错误分成两种 1. 语法错误(这种错误,根本过不了Python解释器的语法检测,必须在程序执行前就改正) #语法错误示范一 if #语法错误示范二 def ...

  4. 2!=5 or 0在python中是否正确-python数据分析第二版:numpy

    一:Numpy #数组和列表的效率问题,谁优谁劣 #1.循环遍历 importnumpy as npimporttime my_arr= np.arange(1000000) my_list= lis ...

  5. 2!=5 or 0在python中是否正确-python中的if判断语句

    判断(if)语句 目标 开发中的应用场景 if 语句体验 if 语句进阶 综合应用 01. 开发中的应用场景 生活中的判断几乎是无所不在的,我们每天都在做各种各样的选择,如果这样?如果那样?--  ...

  6. 2!=5 or 0在python中是否正确-python 中 and or

    在Python 中,and 和 or 执行布尔逻辑演算,如你所期待的一样,但是它们并不返回布尔值:而是,返回它们实际进行比较的值之一. 一.and: 在布尔上下文中从左到右演算表达式的值,如果布尔上下 ...

  7. python中if错误-python中的异常处理

    异常 异常就是程序运行时发生错误的信号,在python中,错误触发的异常如下 异常种类 在python中不同的异常可以用不同的类型(python中统一了类与类型,类型即类)去标识,不同的类对象标识不同 ...

  8. python中语法错误-python冒号语法错误python中如何创建字典

    python字典定义 字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值 key=>value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 ...

  9. python中if错误-Python中错误和异常

    第1章 概念 错误 语法错误:代码不符合解释器或编译器的语法 逻辑错误:不完整或不合法的输入或者计算出现问题 异常:代码执行过程中,出现问题导致程序无法执行 程序遇到逻辑或算法问题 运行过程中计算机错 ...

最新文章

  1. vs配色方案_提高生产力:配色,模板参数过滤及IntelliCode
  2. 【 FPGA 】UltraFast设计方法学:时序收敛之时序约束基本准则
  3. DokiCam 360°4K相机:为极致运动爱好者而生
  4. C++Primer:函数(参数传递:引用形参)
  5. python面向对象(2)—— 继承(3)
  6. Easy.Ajax 部分源代码, 支持文件上传功能, 兼容所有主流浏览器
  7. 【读书笔记】MSDN 上关于加密解密的一个例子
  8. xampp命令行连接MySql数据库
  9. SpringCloud工作笔记040--- XMLHTTP中setRequestHeader()方法解析
  10. c程序设计语言读书笔记,C程序设计语言读书笔记
  11. 手把手学ROR三——Rails的代码方式
  12. php代码上传工具,php中文网重磅推出“php程序员工具箱” v0.1版本!
  13. 【MapReduce】猫眼电影数据库传输数据
  14. 针对测试人员,这些业务安全漏洞你是否会测?
  15. Centos6 yum源设置
  16. Android实现图片轮播
  17. Python 获取当前系统时间
  18. Pybulle中确定UR机械臂末端姿态方法
  19. 《51单片机》用STC-ISP-15XX-V6.85F烧录程序的步骤
  20. Linux网络 DNS域名解析服务

热门文章

  1. 计算机启动过程-阮一峰
  2. STL8-string容器
  3. mysql 导入导出大文件
  4. python 数据库查询返回list或tuple
  5. DataTable操作相关实例
  6. 使用Phantom omni力反馈设备控制机器人
  7. 七月工作笔记 7.7 - 7.11
  8. Altium Designer哪里下载和导入元件库_图文教程
  9. API hook 单步调试
  10. dos命令测试网络连通情况