在"python之禅"那几句话中有一句:namespace is a good thing.
python对于命名空间的处理非常简单,下面的内容不一定真实,完全是我根据现象推测出来的.

一.上来直接调用全局变量

x=[1]
def haha():
   #x=[2]
   x.append('baga')

haha()
print(x)

如果没有注释那句话,输出为[1];如果注释了那句话,输出为[1,'baga'].
这说明python中,有一个命名列表,从内层到外层挨个寻找,直到找到为止.即便整个命名列表中包含很多重复,那也没啥关系,因为默认为最内层的那一个.对于每一层,一个变量名只能对应一个变量,不允许存在多个变量名,即每一层作用域都相当于一个HashMap即class Namespace extends HashMap<String,Object>{},而多层作用域组织起来就是一个栈.Stack<Namespace>namespaceStack.当遇到一个缩进时,向namespaceStack中插入一个Namespace结点,当退回一个缩进时,弹栈一个Namespace结点.
当查找某个变量时,从栈顶向栈底层层搜索各个Namespace,直到找到该变量名为止.

二.进入一个作用域时立即建立Namespace对象且在运行过程中不添加新元素

x = "weidiao"

def haha():
   y=x.upper()
   #x=y

haha()
print(x)

如果注释x=y,代码正常运行;如果不注释这句话,上述代码会报错UnboundLocalError: local variable 'x' referenced before assignment,说x.upper()中的x无法解析.
这说明当python进入一个作用域时,会首先扫描一遍这个作用域,把变量名映射建立起来,但是它们的值都是未绑定状态.

三.告诉python我用的是全局变量

x = "weidiao"

def haha():
   #global x
   x='haha'

haha()
print(x)

如果注释global x,那么haha()函数中定义的x='haha'就会插入到haha的Namespace中去.如果不注释global语句,那么global x相当于告诉编译器,在本作用域内不插入x,这样一来编译器即便扫描到x=也不会将x插入到Namespace中去.因为本作用域内没有x,所以遇到x=这样的赋值语句时,执行的操作就相当于直接对外层变量进行操作.
如果在函数中先定义x=,然后又把global x就会报错,因为在执行global语句时发现没法执行.

四.global是一种指令,一种行为.它影响的是整个函数的Namespace,而不是内层的Namespace

x = "weidiao"

def haha():
   for i in range(3):
      global x
      print(x.upper())
   x='haha'

haha()
print(x)

程序输出为haha
我是在for循环作用域内声明global的,但是这个global却影响了整个函数.这表明global总是作用于函数的Namespace,于是可见Namespace也是分成很多类别的.

五.Namespace的分类

  • 函数的Namespace,称为function类型的namespace
  • for,if,while的Namespace,统一为block类型的namespace
  • 类的Namespace,称为class类型的namespace

在java中,function的namespace不能跟block的namespace有同名元素(编译报错),function namespace可以跟class namespace有同名元素,block namespace也可以跟class namespace有重名元素.
在python中,block namespace和function namespace可以包含同名元素.一切都是简单化处理.

六.伪代码实现python中的命名作用域机制

class Namespace(set):
   def __init__(self, type):
      self.type = type  # 定义命名空间的类型

   def insert(self, name):
      self[name] = unasigned  # 插入一个变量名,默认它是未赋值的

class FunctionNameSpace(Namespace):
   def __init__(self):
      Namespace.__init__("function")
      self.globalList = []  # 函数命名空间都有一个globalList

stack = Stack < Namespace > ()

def getVar(name):
   for namespace in stack:
      if namespace.contains(name):
         return namespace[name]
   raise("undefined variable %s"%name)

def processLine(line):
   if line is "global sentence":
      ns = stack.getTopFunctionNamespace()  # 获取栈顶第一个函数命名空间
      if ns.contains(line.globalName):
         if ns[line.globalName].unasigned:  # 如果存在这样的局部变量但是未曾赋值则删掉
            ns.remove(line.globalName)
         else:  # 已经存在的局部变量且已赋值,则报错无法声明global
            raise Exception("SyntaxWarning: name '%s' is assigned to before global" % line.globalName)
      else:
         ns.globalList.append(line.globalName)  # 添加到全局变量表中
   else:
      pass

def parseFunction(src):
   for line in src:
      if line.indent.delta == 0:#本行缩进变化量为0
         process(line)
      elif line.indent.delta == 1:#本行缩进变化量为1,即多缩进了一个tab
         ns = Namespace("block")
         for l in line.nextLinesWithSameIndent:
            if l is "assign sentence":
               ns.push(l.name)
         stack.push(ns)
         process(line)
      elif line.indent.delta < 0:#本行缩进变化量为负数,即回退了delta个,需要弹栈
         for i in range(line.indent.delta, 0):
            stack.pop()
         process(line)

python命名空间的更多相关文章

  1. python命名空间与作用域

    python命名空间与作用域   命名空间是名称与对象之间的关系,可以将命名空间看做是字典,其中的键是名称,值是对象. 命名空间不共享名称. 在命名空间中的名称能将任何python对象作为值,在不同的 ...

  2. python命名空间的本质

    Python的命名空间是Python程序猿必须了解的内容,对Python命名空间的学习,将使我们在本质上掌握一些Python中的琐碎的规则. 接下来我将分四部分揭示Python命名空间的本质:一.命名 ...

  3. [Python] 命名空间&作用域

    Python的类语句不会创建实例 类会创建命名空间,通过对象访问类的属性和方法 类不会创建作用域,对方法和属性的引用必须加以限定(如在方法中必须通过self引用实例的属性) class My1(): ...

  4. Python 命名空间

    通俗的来说,Python中所谓的命名空间可以理解为一个容器.在这个容器中可以装许多标识符.不同容器中的同名的标识符是不会相互冲突的.理解python的命名空间需要掌握三条规则: 第一,赋值(包括显式赋 ...

  5. 详解python命名空间和作用域

    1.典型案例 先从几个典型的案例来看下名称空间及作用域对python代码运行的影响,请看下面几个代码实例及其执行结果,是否符合你的预期. 代码1:块作用域 if True: i = 1 print i ...

  6. python类和模块区别,python命名空间

    在python中,类可以提供模块级别之下的命名空间. 如果一个模块写很多函数,某些函数之间共同完成一组功能,用类会看起来更清晰,在调用时候也会更好,对于ide补全有更小范围的限定提示. 类提供 继承 ...

  7. python—命名空间、作用域查找顺序、闭包

    名称空间 name space,如下图: x = 1, 1存放在内存中,1 会有一个内存地址,x 则 存放在 name space 里,并同时记录了 1的内存地址, 即 名称空间是存放了变量x与1绑定 ...

  8. python命名空间、作用域、闭包与传值传引用

    (以下内容,均基于python3) 最近在看python函数部分,讲到了python的作用域问题,然后又讲了Python的闭包问题. 在做作业的时候,我遇到了几个问题,下面先来看作业. 一. 作业1: ...

  9. Python命名空间和作用域

    准备知识: 1.在Python解释器开始执行之后,机会在内存中开辟一个空间,每当遇到 一个变量的时候,就把变量和值之间的关系记录下来,但是当遇到函数定义 的时候,解释器只是把函数名读入内存,表示这个函 ...

随机推荐

  1. 简简单单学会C#位运算

    一.理解位运算 要学会位运算,首先要清楚什么是位运算?程序中的所有内容在计算机内存中都是以二进制的形式储存的(即:0或1),位运算就是直接对在内存中的二进制数的每位进行运算操作 二.理解数字进制 上面 ...

  2. express路由探析(续)

    上一篇分析了express的路由机制,这次主要补充一些没有说到的东西. 之前说到,Router是中间件容器,Route是路由中间件,他们各自维护一个stack数组,里面存放layer,layer是封装 ...

  3. 用python实现逻辑回归

    机器学习课程的一个实验,整理出来共享. 原理很简单,优化方法是用的梯度下降.后面有测试结果. # coding=utf-8 from math import exp import matplotlib ...

  4. Lua 安全调用 metatable 的简单应用

    事情的经过 我们的项目中存在好几个战斗界面,不过界面中的内容略有不同.跟同事出去吃饭的时候,他问我.我们现在的战斗界面.有很多是重复的,但是也有偶尔几个地方不太一样.我在战斗过程中驱动这些界面的时候. ...

  5. .Net语言 APP开发平台——Smobiler学习日志:如何实现离线声音文件上传

    最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 一.目标样式 我们要实现上图中的效果,需要如下的操作: 1.从工具栏上的"S ...

  6. 关于 ASP.NET MVC 中的视图生成

    在 ASP.NET MVC 中,我们将前端的呈现划分为三个独立的部分来实现,Controller 用来控制用户的操作,View 用来控制呈现的内容,Model 用来表示处理的数据. 从控制器到视图 通 ...

  7. Java Swing interview

    http://www.careerride.com/Swing-AWT-Interview-Questions.aspx   Swing interview questions and answers ...

  8. java 开发模式

    Java-开发模式 Java Web开发方案有多种,这里列举一些经典的开发模式进行横向比较JSP+JAVABEAN开发模式:    特点:该模式将业务逻辑与页面表现进行分离,在一定程度上增加了程序的可 ...

  9. Mysql性能优化一

    下一篇:Mysql性能优化二 mysql的性能优化无法一蹴而就,必须一步一步慢慢来,从各个方面进行优化,最终性能就会有大的提升. Mysql数据库的优化技术 对mysql优化是一个综合性的技术,主要包 ...

  10. 高性能 TCP & UDP 通信框架 HP-Socket v3.5.1

    HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Del ...