Python 2.x嵌套作用域的限制

python是一门静态作用域的语言,PEP 227在python 2.1开始引入了一项语言新特性——静态嵌套作用域

当然,新特性也伴随而来了一些新问题。在函数作用域内执行bare execimport *的时候,可能会在local namespace中创建新的名称。但由于是动态语句,python在编译时无法确定是否真的会创建新名称,所以也就无法在编译时确定嵌套函数中的名称绑定。

比如下面inner函数中的名称x,编译时无法确定是否应该绑定到global namespace的名称x,因为exec str可能会在local namespace中也创建名称x

x = 1
def outer(str):
    exec str          # str = 'x=2'
    def inner():
        print x

这种情况下有两种策略:

  1. 编译时放任不管,运行时再根据实际情况绑定

    这会导致人在看代码的时候,也无法确定inner函数内的名称x到底如何绑定,同时也违背了python的静态作用域设计目标

  2. 编译时直接强行静态绑定,忽略动态语句可能的影响

    如果动态语句真的在当前作用域中创建了新的名称绑定,那这些名称就对当前作用域中的嵌套作用域不可见了,这违背了PEP 227本身的设计目标

两种策略各有弊病,所以PEP 227最终决定:

SyntaxError: unqualified exec is not allowed in function 'xxxx' because it contains a nested function with free variables

根据这个异常提示信息,也可以反过来总结出抛异常的两个条件:

  1. bare execunqualified exec),或者import *
  2. 嵌套函数内部引用了自由变量,也就是外部名称

要解决这个问题,只需使用exec ... in ...语句就可以了。这样exec语句就能保证不会对local namespace产生任何影响(修改locals()不会真的影响局部变量),编译器就能放心的忽略exec语句的影响而直接静态绑定了。这也是为什么exec需要是个关键字而不是库函数。

其实这种方法跟上面说的第二种策略是一个意思,只不过把控制权从编译器交给了开发者。

python 3中对exec语义做了一些修改,就不存在这个问题了,所以它不需要再是关键字,变成了一个函数。

详情参见PEP 227 – Statically Nested Scopes

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值