• python命名空间


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

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

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

    如果没有注释那句话,输出为[1];如果注释了那句话,输出为[1,'baga'].
    这说明python中,有一个命名列表,从内层到外层挨个寻找,直到找到为止.即便整个命名列表中包含很多重复,那也没啥关系,因为默认为最内层的那一个.对于每一层,一个变量名只能对应一个变量,不允许存在多个变量名,即每一层作用域都相当于一个HashMap<String,Object>即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)
    
    
  • 相关阅读:
    fork()和vfork()的区别(转载)
    Linux中fork()函数详解(转载)
    ERROR:Simulator861-Failed to link the design解决办法
    ISE 14.7安装教程最新版(Win10安装)
    实验2用户及文件权限管理
    检验
    实验1基本概念及操作
    日常学习笔记(2)
    日常笔记1
    拷贝初始化的几种情况
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/6105603.html
Copyright © 2020-2023  润新知