python做用域 scope

能够先看:http://www.cnblogs.com/youxin/p/3645734.htmlhtml

几个概念:
python可以改变变量做用域的代码段是def、class、lamda.
if/elif/else、try/except/finally、for/while 并不能涉及变量做用域的更改,也就是说他们的代码块中的变量,在外部也是能够访问的
变量搜索路径是:本地变量->全局变量python

做用域搜索规则:web

LEGB Rule.闭包

L. Local. (Names assigned in any way within a function (def or lambda)), and not declared global in that function.app

E. Enclosing function locals. (Name in the local scope of any and all enclosing functions (def or lambda), form inner to outer.ide

“封闭式”的做用域规则适应于函数定义函数时,也就是说,在函数体内定义了一个新的函数。这个函数体内的函数是外函数的局部命名空间中的一部分,意味着只有在外函数执行期间才可以运行函数

G. Global (module). Names assigned at the top-level of a module file, or declared global in a def within the file.post

B. Built-in (Python). Names preassigned in the built-in names module : open,range,SyntaxError,ui

 

下面一个程序,运行时为何报错:this



def func1(param=None): def func2(): if not param: param = 'default' print param # Just return func2. return func2 if __name__ == '__main__': func1('test')()

为何?param是func1的。
先看下面的相似例子:Traceback (most recent call last): File "test.py", line 11, in func1('test')() File "test.py", line 3, in func2 if not param: UnboundLocalError: local variable 'param' referenced before assignment
def foo():
    m=3
    def bar():
        
        a=4
        return a+m
    return bar
foo()()

运行正常,但是若是加上一句:

if not m:
            m=1
马上报相似错误:UnboundLocalError: local variable 'm' referenced before assignment。
错误的缘由是python闭包原理;
def foo():
    m=3
    n=5
    def bar():
        a=4
        return m+n+a
    return bar

>>>bar =  foo()
>>>bar()
12
cell对象的引入,是为了实现被多个做用域引用的变量。
对每个这样的变量,都用一个cell对象来保存 其值 。

拿以前的示例来讲,m和n既在foo函数的做用域中被引用,又在bar
函数的做用域中被引用,因此m, n引用的值,都会在一个cell对象中。
这两个int型的cell分别存储了m和n的值。
不管是在外部函数中定义,仍是在内部函数中调用,引用的指向都是cell对象中的值。

内部函数没法修改cell对象中的值,若是尝试修改m的值,编译器会认为m是函数
bar的局部变量,同时foo代码块中的m也会被认为是函数foo的局部变量,两个m分别在各自的做用域下起做用。

因此咱们看到了:

if not param:

        param=5

尝试给param赋值,param就成了局部变量,那么以前的if  not param就报错,由于param尚未赋值。仍是不清楚为何?参考:http://www.cnblogs.com/btchenguang/archive/2012/08/29/2662571.html

隔几天有发现了答案:

http://www.cnblogs.com/youxin/p/3383059.html


你也许正疑惑为何咱们的计数器是  的一个属性而不是一个普通的变量。难道  的闭包环境不是让咱们访问在其局部做用域中声明的任意变量么?是的,但有个问题。def logging_decorator(func): def wrapper(): wrapper.count += 1 print "The function I modify has been called {0} time(s)".format(wrapper.count) func() wrapper.count = 0
return wrapper def a_function(): print "I'm a normal function."wrapperwrapper

但有个问题。Python中,闭包容许对其函数做用域链中任一变量的进行任意读操做,但只容许对可变对象(列表、字典、等等)进行写操做。整数在Python中是非可变对象,所以咱们不能修改 wrapper 内部整型变量的值。相反,咱们将计数器做为 wrapper 的一个属性—一个可变对象,所以能够随咱们本身增大它的值。。

def func1():
    param=[1,2]
    def func2():
         
        if not param:
           param.append(5)
       
        
        print param
    #just return func2
    return func2
 
func1()();

程序运行正常。

若是改为:

if not param:

  param=[3,4]

仍是报一样的错。

因此,闭包对外部的可变变量不能使用=赋值,能够修改。

 

If you’re curious, you can read about the principles of LEGB. You have to understand a bit about compilers and the AST to get what’s going on behind the scenes. You might think that replacing lines 3-4 with:

param = param or 'default'

 

Might work. But no. You can’t assign the same parameter at the local level if the enclosing level defines it. Even this fails:

param = param

What to do?

There are a few ways to get around this.

  • Assign param outside of func2. This doesn’t work if you need the default value to be dependent on what params func2 receives.
  • Use a second variable, param2 inside of func2 (posted below).

Here is the solution suggested by our commenter Avazu:

def func1(param=None):
    def func2(param2=param):
        if not param2:
            param2 = 'default'
        print param2
    # Just return func2.
    return func2
上面例子参考:http://blog.mozilla.org/webdev/2011/01/31/python-scoping-understanding-legb/
相关文章
相关标签/搜索