Python 作用域和命名空间
在介绍类之前,我首先要告诉你一些Python的作用域规则。类定义对命名空间有一些巧妙的技巧,你需要知道作用域和命名空间如何工作才能完全理解正在发生的事情。顺便说一下,关于这个主题的知识对任何高级Python程序员都很有用。
让我们从一些定义开始。
namespace 是一个从名字到对象的映射。大部分命名空间当前都由 Python 字典实现,但一般情况下基本不会去关注它们(除了要面对性能问题时),而且也有可能在将来更改。下面是几个命名空间的例子:存放Python内置函数的集合(包含 abs()
这样的函数,和内建的异常等);模块中的全局名称;函数调用中的本地名称。从某种意义上说,对象的的属性集合也是一种命名空间的形式。关于Python命名空间的重要一点是,不同命名空间中的名称之间绝对没有关系;例如,两个不同的模块都可以定义函数“最大化”而不会产生混淆 - 模块的用户必须在其前面加上模块名称。
顺便说明一下,我把任何跟在一个点号之后的名称都称为 属性 --- 例如,在表达式 z.real
中,real
是对象 z
的一个属性。按严格的说法,对模块中名称的引用属于属性引用:在表达式 modname.funcname
中,modname
是一个模块对象而 funcname
是它的一个属性。在此情况下在模块的属性和模块中定义的全局名称之间正好存在一个直观的映射:它们共享相同的命名空间!
属性可以是只读或者可写的。如果为后者,那么对属性的赋值是可行的。模块属性是可以写,你可以写出 modname.the_answer = 42
。可写的属性同样可以用 del
语句删除。例如, del modname.the_answer
将会从名为 modname
的对象中移除 the_answer
属性。
在不同时刻创建的命名空间拥有不同的生存期。包含内置名称的命名空间是在 Python 解释器启动时创建的,永远不会被删除。模块的全局命名空间在模块定义被读入时创建;通常,模块命名空间也会持续到解释器退出。被解释器的顶层调用执行的语句,从一个脚本文件读取或交互式地读取,被认为是 __main__
模块调用的一部分,因此它们拥有自己的全局命名空间。(内置名称实际上也存在于一个模块中;这个模块称作 builtins
。)
python教程,一个函数的本地命名空间在这个函数被调用时创建,并在函数返回或抛出一个不在函数内部处理的错误时被删除。(事实上,比起描述到底发生了什么,忘掉它更好。)当然,每次递归调用都会有它自己的本地命名空间。
一个 作用域 是一个命名空间可直接访问的 Python 程序的文本区域。 这里的 “可直接访问” 意味着对名称的非限定引用会尝试在命名空间中查找名称。
Although scopes are determined statically, they are used dynamically. At any time during execution, there are at least three nested scopes whose namespaces are directly accessible:
- 最先搜索的最内部作用域包含局部名称
- 从最近的封闭作用域开始搜索的任何封闭函数的范围包含非局部名称,也包括非全局名称
- 倒数第二个作用域包含当前模块的全局名称
- 最外面的范围(最后搜索)是包含内置名称的命名空间
如果一个名称被声明为全局变量,则所有引用和赋值将直接指向包含该模块的全局名称的中间作用域。 要重新绑定在最内层作用域以外找到的变量,可以使用 nonlocal
语句声明为非本地变量。 如果没有被声明为非本地变量,这些变量将是只读的(尝试写入这样的变量只会在最内层作用域中创建一个 新的 局部变量,而同名的外部变量保持不变)。
通常,当前局部作为域将(按字面文本)引用当前函数的局部名称。 在函数以外,局部作用域将引用与全局作用域相一致的命名空间:模块的命名空间。 类定义将在局部命名空间内再放置另一个命名空间。
重要的是应该意识到作用域是按字面文本来确定的:在一个模块内定义的函数的全局作用域就是该模块的命名空间,无论该函数从什么地方或以什么别名被调用。 另一方面,实际的名称搜索是在运行时动态完成的 --- 但是,语言定义在 编译时 是朝着静态名称解析的方向演化的,因此不要过于依赖动态名称解析! (事实上,局部变量已经是被静态确定了。)
Python 的一个特殊之处在于 -- 如果不存在生效的 global
语句 -- 对名称的赋值总是进入最内层作用域。 赋值不会复制数据 --- 它们只是将名称绑定到对象。 删除也是如此:语句 del x
会从局部命名空间的引用中移除对 x
的绑定。 事实上,所有引入新名称的操作都使用局部作用域:特别地,import
语句和函数定义会在局部作用域中绑定模块或函数名称。
global
语句可被用来表明特定变量生存于全局作用域并且应当在其中被重新绑定;nonlocal
语句表明特定变量生存于外层作用域中并且应当在其中被重新绑定。
9.2.1. 作用域和命名空间示例
This is an example demonstrating how to reference the different scopes and namespaces, and how global and nonlocal affect variable binding: def scope_test():
def do_local():
spam = "local spam" def do_nonlocal():
nonlocal spam
spam = "nonlocal spam" def do_global():
global spam
spam = "global spam" spam = "test spam"
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam) scope_test()
print("In global scope:", spam)
示例代码的输出是:
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
请注意 局部 赋值(这是默认状态)不会改变 scope_test 对 spam 的绑定。 nonlocal
赋值会改变 scope_test 对 spam 的绑定,而 global
赋值会改变模块层级的绑定。
您还可以在 global
赋值之前看到之前没有 spam 的绑定。
Python 作用域和命名空间的更多相关文章
- python 作用域与命名空间
作用域 作用域分为: 全局作用域 局部作用域 在函数内部的作用域叫做局部作用域,局部作用域中的变量叫做局部变量 非函数内部的作用域叫做全局作用域,全局作用域中的变量叫做全局变量 局部作用域可以使用全局 ...
- python作用域与命名空间
什么是命名空间 比如有一个学校,有10个班级,在7班和8班中都有一个叫“小王”的同学,如果在学校的广播中呼叫“小王”时,7班和8班中的这2个人就纳闷了,你是喊谁呢!!!如果是“7班的小王”的话,那么就 ...
- python 作用域,命名空间
def scope_test(): def do_local(): spam = "local spam" def do_nonlocal(): nonlocal spam spa ...
- Python3.2官方文档翻译--作用域和命名空间
6.2 Python作用域和命名空间 在介绍类之前.首先我想告诉你一些关于python作用域的规则. 类的定义很巧妙地运用了命名空间,你须要知道范围和命名空间的工作原理以能全面了解接下来发生的. 顺便 ...
- 详解Python的作用域和命名空间
最近在学习Python,不得不说,Python真的是一门很好用的语言.但是学习的过程中关于变量作用域(scope)的命名空间(namespace)的问题真的把我给搞懵了.在查阅了相关资料之后,觉得自己 ...
- 九. Python基础(9)--命名空间, 作用域
九. Python基础(9)--命名空间, 作用域 1 ● !a 与 not a 注意, C/C++可以用if !a表示if a == 0, 但是Python中只能用if not a来表示同样的意义. ...
- python作用域问题
今天出了个低级的错误,最后确定是作用域问题,特回顾知识点如下: 在Python程序中创建.改变.查找变量名时,都是在一个保存变量名的空间中进行,我们称之为命名空间,也被称之为作用域. Python的作 ...
- python基础-3 集合 三元运算 深浅拷贝 函数 Python作用域
上节课总结 1 运算符 in 字符串 判断 : “hello” in "asdasfhelloasdfsadf" 列表元素判断:"li" in ['li', ...
- 13.Python中的命名空间是什么
Python中的命名空间是什么? In Python,every name introduced has a place where it lives and can be hooked for. T ...
随机推荐
- [转]GeoServer地图开发解决方案(一):环境搭建篇
GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新.删除.插入操作,通过 GeoS ...
- [转] 各种Json解析工具比较 - json-lib/Jackson/Gson/FastJson
JSON技术的调研报告 一 .各个JSON技术的简介和优劣1.json-libjson-lib最开始的也是应用最广泛的json解析工具,json-lib 不好的地方确实是依赖于很多第三方包,包括com ...
- Lua库-bit32库
Global = Global or {}; local bits = {}; function bits.bxor(num1,num2) local ret=bit32.bxor(num1,num2 ...
- Docker 三种UI管理平台
docker集中化web管理平台 一.shipyard 1.启动docker,下载镜像 # systemctl restart docker # docker pull alpine # docker ...
- oracle11g的安装与卸载
1.首先确认电脑已安装 .NET Framework3.5 2.本地计算机的安装: 参考:https://www.cnblogs.com/hoobey/p/6010804.html 3.服务器的安装: ...
- Xcode 9.3 pod install update 错误
[!] Oh no, an error occurred. Search for existing GitHub issues similar to yours: https://github.com ...
- 806. Number of Lines To Write String (5月24日)
解答 class Solution { public: vector<int> numberOfLines(vector<int>& widths, string S) ...
- ABAP术语-Technical Object
Technical Object 原文:http://www.cnblogs.com/qiangsheng/archive/2008/03/18/1111205.html Generic term f ...
- 记一次MySQL中Waiting for table metadata lock问题的处理
起因:由于需要,要把一张表的一个字段从不是 null 改成 可null,我用的Navicat Premium ,但是在保存的时候,工具无响应了,几个同事操作都是这样的,很奇怪,怀疑是不是由于表被锁了还 ...
- systemd的新特性及常见的systemd unit类型分析
systemd概述 )systemd是一种新的linux系统服务管理器,用于替换init系统,能够管理系统启动过程和系统服务,一旦启动起来,就将监管整个系统.在centos7系统中,PID1被syst ...