zoukankan      html  css  js  c++  java
  • 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)
    
    
  • 相关阅读:
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    mysql备份及恢复
    mysql备份及恢复
    mysql备份及恢复
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/6105603.html
Copyright © 2011-2022 走看看