从局部变量和全局变量开始全面解析Python中变量的作用域
理解全局变量和局部变量 num = 100 def func(): num = 123 print num func() 输出结果是123。说明函数中定义的变量名num是一个局部变量,覆盖全局变量。再例如: num = 100 def func(): num += 100 print num func() 输出结果是:UnboundLocalError: local variable 'num' referenced before assignment。提示错误:局部变量num在赋值前被应用。也就是说该变量没有定义就被错误使用。由此再次证明这里定义的是一个局部变量,而不是全局变量。 2.函数内部的变量名如果是第一次出现,且出现在=符号后面,且在之前已被定义为全局变量,则这里将引用全局变量。例如: num = 100 def func(): x = num + 100 print x func() 输出结果是200。如果变量名num在之前没有被定义为全局变量,则会出现错误提示:变量没有定义。例如: def func(): x = num + 100 print x func() 输出结果是:NameError: global name 'num' is not defined。 3.函数中使用某个变量时,如果该变量名既有全局变量也有局部变量,则默认使用局部变量。例如: num = 100 def func(): num = 200 x = num + 100 prinx x func() 输出结果是300。 4.在函数中将某个变量定义为全局变量时需要使用关键字global。例如: num = 100 def func(): global num num = 200 print num func() print num 输出结果分别是200和200。这说明函数中的变量名num被定义为全局变量,并被赋值为200。再例如: num = 100 def func(): global num num = 200 num += 100 print num func() print num 输出结果分别是300和300。 结合上文对全局变量和局部变量的应用场景的整理结果,我尝试对input fields中的教学代码的前半部分做一些分析(中文部分的注释): # calculator with all buttons import simplegui # intialize globals store = 0 operand = 0 这里调用了simplegui模块,可以在http://www.codeskulptor.org/操作无误。但是该模块无法直接在python环境中使用,需要先安装SimpleGUICS2Pygame包。 # event handlers for calculator with a store and operand def output(): """prints contents of store and operand""" print "Store = ",store print "Operand = ",operand print "" 在定义的函数output()中直接使用了全局变量store和operand。可以参考第2点。 def swap(): """ swap contents of store and operand""" global store,operand store,operand = operand,store output() 在定义的函数swap()中首先对store和operand做了全局变量的定义。如果不这样操作,那么就会出现没有赋值就被使用的错误提示。可以参考第1点。同时是不是可以这样理解:函数swap()中,在没有关键字global的情况下,store和operand是默认局部变量,而=右边的部分在没有赋值的情况被使用是错误的。可以参考第3点。 def add(): """ add operand to store""" global store store = store + operand output() 在这里我碰到了两周课程学习以来的第一个难题:那就是为什么add()函数中只定义了store为全局变量,而没有相同地去定义operand。现在结合第1点来看,是因为store作为局部变量没有事先赋值,不能直接使用,而operand是可以直接调用之前定义的全局变量来使用的。 变量作用域 L (Local) 局部作用域 Python除了def/class/lambda 外,其他如: if/elif/else/ try/except for/while并不能改变其作用域。定义在他们之内的变量,外部还是可以访问。 >>> if True: ... a = 'I am A' ... >>> a 'I am A' 定义在if语言中的变量a,外部还是可以访问的。 g = 1 #全局的 def fun(): g = 2 #局部的 return g print fun() # 结果为2 print g # 结果为1 但是要注意,有时候想在函数内部引用全局的变量,疏忽了就会出现错误,比如: #file1.py var = 1 def fun(): print var var = 200 print fun() #file2.py var = 1 def fun(): var = var + 1 return var print fun() 这两个函数都会报错UnboundLocalError: local variable 'var' referenced before assignment 闭包Closure 函数嵌套/闭包中的作用域: a = 1 def external(): global a a = 200 print a b = 100 def internal(): # nonlocal b print b b = 200 return b internal() print b print external() 一样会报错- 引用在赋值之前,Python3有个关键字nonlocal可以解决这个问题,但在Python2中还是不要尝试修改闭包中的变量。 关于闭包中还有一个坑: from functools import wraps def wrapper(log): def external(F): @wraps(F) def internal(**kw): if False: log = 'modified' print log return internal return external @wrapper('first') def abc(): pass print abc() 也会出现 引用在赋值之前 的错误,原因是解释器探测到了 if False 中的重新赋值,所以不会去闭包的外部函数(Enclosing)中找变量,但 if Flase 不成立没有执行,所以便会出现此错误。除非你还需要else: log='var' 或者 if True 但这样添加逻辑语句就没了意义,所以尽量不要修改闭包中的变量。 好像用常规的方法无法让闭包实现计数器的功能,因为在内部进行 count +=1 便会出现 引用在赋值之前 的错误,解决办法:(或Py3环境下的 nonlocal 关键字) def counter(start): count =[start] def internal(): count[0] += 1 return count[0] return internal count = counter(0) for n in range(10): print count() # 1,2,3,4,5,6,7,8,9,10 count = counter(0) print count() # 1 由于 list 具有可变性,而字符串是不可变类型。 locals() 和 globals() 比如:如果函数1内需要定义一个局部变量,名字另一个函数2相同,但又要在函数1内引用这个函数2。 def var(): pass def f2(): var = 'Just a String' f1 = globals()['var'] print var return type(f1) print f2() # Just a String # <type 'function'> locals() @app.route('/') def view(): user = User.query.all() article = Article.query.all() ip = request.environ.get('HTTP_X_REAL_IP',request.remote_addr) s = 'Just a String' return render_template('index.html',user=user,article = article,ip=ip,s=s) #或者 return render_template('index.html',**locals()) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |