Python Namespace and Scope

我感觉很多英文名词翻译过来可能会引起误解,因为大家的背景各异,看过的书也不一样,对名词的理解也有差异,为了表述不会引起歧义,对于一些名词,文中全都用英文。

name(也叫 identifier)只是 objects 的 Name。这个解释跟没有解释一样。但是在python中, 所有的东西都是一个 object。name 仅仅是对内存中 object 的引用。

比如,一个简单的赋值操作 a = 2,这里的 2 是保存在内存中的一个object,a 则是对 2 的引用。我们可以用 python内置的函数 id() 去得到内存中对象的地址: 比如下面的代码:

>>> a = 2
>>> id(a)
23159120
>>> id(2)
23159120
>>>

从上面的代码我们可以看出,object 2 在内存中的地址是 23159120,a 指向的 object 内存地址也是 23159120, 它们代表的是同一个object。下面在看几个例子:

>>> a = 2
>>> id(a)
23159120
>>> a += 1
>>> id(a)
23159096
>>> id(3)
23159096
>>> id(2)
23159120
>>> b = 2
>>> id(b)
23159120

这里发生了什么?用一张图说话吧!

1  a = 2, 在内存中创建一个 object,a 指向这个 object。当执行  a += 1,内存中产生一个新的 object 3,然后 a 指向 object 3 。所以 a 和 3 的内存地址是一样的。

2 b = 2,内存中已经存在 object 2了,直接将它的引用赋值给 b。

python 为什么这么做呢?效率!内存中已经存在2 这个object了,在创建一个是浪费内存,直接把2的引用给b就行了,没必要重新创建一个。因此python中的 name 可以引用任何类型的object。这个会给有过 C java scala 编程经验的人很大困惑。其实python中的name仅仅是对内存中object 引用,object 的类型是object,name 是不存在类型的。那么 name 指向的类型是如何确定的呢? python运行时确定,这个就是python的强大之处,体现了它动态的特性。

>>> a = 5
>>> a = ‘Hello World!‘
>>> a = [1,2,3]

上面的几个例子在c/c++肯定是错的,但是在python中这么写完全没问题。因为python中一切皆是object,因此function也是object,所以name也可以指向function。

>>> def printHell():
...     print ‘Hello‘
...
>>> a = printHell()
Hello

那么什么是 namespace 呢?

已经讲过name是什么了,下面来谈谈 namespace。

简单的说, namespace 就是 name 集合。

在python中,你可以将 namespace 想象成  name 到 object 的映射。

不同的 namespace 可以同时存在,但是它们必须完全隔离开来,否则会造成冲突。

当我们启动python 解释器的时候会创建一个namespace,这个namespace含有python所有的内置 name,只要程序不退出,这个namespace就一直存在。因此我们在程序的任何地方都可以调用 id()和print()。每个module也创建它自己的global namespace。

这些不同的namespace是互相隔离的,因此,同样的 name 可以存在不同的module中而不会引起冲突。

module 中有各种各样 function 和 class。当调用一个 function 时,python会创建一个 local namespace, 这个function定义的所有 name 都在这个 local namespace中。同样的, class 和 function也是一样。

python 变量 scope

程序中虽然存在各种各样的 namespace,但是我们的程序也许并不可能去访问每一个 namspace。这个就是 scope 的概念。

scope就是不需要任何前缀名就可以访问namespace中的name 的代码块。这句确实不好翻译,原文为:Scope is the portion of the program from where a namespace can be accessed directly without any prefix. 一共有三种scope:

1 当前function的scope,其中含有 local name

2 模块scope,有 global name

3 最外层的scope,有 内置的 name

当一个name出现在function中,python先在 local namespace中搜索它,然后是 global namespace,最后在 内置的 namespace,如果还找不到就报错。

def outer_function():
    b = 20
    def inner_func():
        c = 30

a = 10

上面的代码,a 在 global namespace 中,变量 b 在 function outer_function 的 local namespace 中, c 在 inner_function() 的local namespace 中。在 function  inner_function 中,c 是 local namespace,b 是  nonlocal , a 是 global,我们可以给c赋值,但是对于 b 和 c 则是只读。

在 inner_function 中如果我们试图给 b 赋予一个新的值,那么python会在 local namespace 中新建一个name  b,这个b和 out_function中的b是不同的。a 同理。请看下面这个例子:

>>> def out_function():
...     a = 20
...     def inner_function():
...             a = 30
...             print ‘a = %s‘ % a
...     inner_function()
...     print ‘a = %s‘ % a
...
>>> out_function()
a = 30
a= 20
>>> a = 10
>>> out_function()
a = 30
a = 20
>>> print ‘a = %s‘ % a
a = 10

上面这个例子中的 a ,都是在各自不同 namespace 中。

如果我们将 a 声明为 global,则所有的赋值和引用操作都将指向 global a。

>>> def outer_function():
...     global a
...     a = 20
...     def inner_function():
...         global a
...         a = 30
...         print ‘a = %s‘ % a
...     inner_function()
...     print ‘a = %s‘ % a
...
>>> a = 10
>>> outer_function()
a = 30
a = 30
>>> print(‘a =‘,a)
a = 30

因为在local namespace 中将a声明为 global,所以它会去global namespace中去寻找而不是自己重新创建,如果找不到就会报错。

本文翻译于:https://www.programiz.com/python-programming/namespace

时间: 2024-10-21 06:53:21

Python Namespace and Scope的相关文章

Python Namespace - 命名空间

命名空间 命名空间 namespace 对 python 来说是一个非常核心的概念,整个 python 虚拟机运行的机制与 namespace 概念有这非常紧密的联系. 从'赋值'说起, python 中的赋值语句是一类特殊的语句,原因是因为它们会影响 namespace. python 中的赋值语句首先创建一个 对象 object,然后将 obj '赋值' 给一个名字 name (理解为赋值给一个变量) 赋值语句执行后, 我们的一个 name 和 object 的关联关系, 称之为'约束',

Python标准库--Scope

1 模块简介 你一定在很多计算机科学课程上听说过作用域.它很重要,如果你不理解它的工作原理,那么就会出现一些令人困惑的错误.作用域最基本的功能就是告诉编译器一个变量什么时候是可见的.也就是说,作用域定义了你使用变量的时间和范围.当你尝试使用一些不在当前作用域的变量时,你就会得到NameError. Python有三类作用域: 局部作用域: 全局作用域: 非局部作用域(Python 3 中新增): 2 模块使用 2.1 局部作用域 局部作用域是Python中使用最多的作用域.当你在一段代码块中创建

Python Scopes and Namespaces

Before introducing classes, I first have to tell you something about Python's scope rules. Class definitions play some neat tricks with namespaces, and you need to know how scopes and namespaces work to fully understand what's going on. Incidentally,

python 下的数据结构与算法---1:让一切从无关开始

我也忘了大概多久了,好像是三周多一点,终于把Data Structure and Algorithms with python以及 Problem Solving with  Algorithms and DataStructures看完了(图那部分没仔细看,太难太费时间,毕业设计开始了,有点忙).[github地址,包含了那两本书带笔记版以及下面零的代码] 所以啦,这作为第一篇总结笔记就从点无关的开始吧(也就是这两本书中提到的python相关但是与数据结构和算法无关的东东) 目录: 零:有些什

c#中调用python

1. 安装IronPython,到http://ironpython.codeplex.com/下载安装包 2. 创建项目 创建一个C#的控制台应用程序. 添加引用: 浏览到IronPython的安装目录中,添加对IronPython.dll,Microsoft.Scripting.dll 两个dll的引用. 3. 添加Python文件到当前的项目中 创建一个文本文件命名为:hello.py, 编辑如下 def welcome(name):    return "hello" + na

C#脱离IronPython中执行python脚本

给客户安装程序时除了安装.net framework还要安装IronPython,是不是觉得很麻烦? 上面这一切都弱爆了,下面我来介绍一种不安装IronPython只需要引入几个IronPython的dll就可以在c#中执行python脚本的方法. 1:引入IronPython中的几个dll 2:进入IronPython的Lib文件夹,把Lib中的内容打包成zip,名字任意既可.打包好后放到c#项目下 我把它放到了和py文件同一个目录中 3:很关键的一步,程序初始化时执行下段代码 ScriptE

Python Monkey patch猴子补丁

monkey patch (猴子补丁)   用来在运行时动态修改已有的代码,而不需要修改原始代码. 简单的monkey patch 实现:[python] #coding=utf-8 def originalFunc():     print 'this is original function!'      def modifiedFunc():     modifiedFunc=1     print 'this is modified function!'      def main():

【Python笔记】Python的几个高级语法概念浅析:lambda表达式 && 闭包 && 装饰器

本文主要记录自己对几个高级语法概念的理解:匿名函数.lambda表达式.闭包.装饰器. 这几个概念并非Python特有,但本文只限于用Python做说明. 1. 匿名函数 匿名函数(anonymous function)是指未与任何标识符绑定的函数,多用在functional programming languages领域,典型应用场合: 1) 作为参数传给高阶函数(higher-order function ),如python中的built-in函数filter/map/reduce都是典型的

`python`被`C# `调用的方法

目的: 熟悉markdown 记录python被C#调用的方法 参考材料: markdown语法 python被C#调用的方法(参考自博客内容) 调用方法: 采用Ironpython: 优点: 快捷方便,方便传递参数等,因为相当于是将python代码传递进C#之中进行操作,语法逻辑比较清楚. 缺点: 需要额外配置Ironpython, 且不支持python3.X.不共享系统中安装的python环境包,需要额外配置路径或者重装numpy之类的软件包. 示例代码: using IronPython.