python中的作用域介绍
1、作用域介绍
python中的作用域分4种情况: L:local,局部作用域,即函数中定义的变量;
E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
G:globa,全局变量,就是模块级别定义的变量; B:built-in,系统固定模块里面的变量,比如int, bytearray等。 搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
1 2 3 4 5 6 7 |
x = int(2.9) # int built-in
g_count = 0 # global |
当然,local和enclosing是相对的,enclosing变量相对上层来说也是local。
2、作用域产生
在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如if、try、for等)是不会引入新的作用域的,如下代码:
1 2 3 4 |
if True: x = 1; print(x) # 1 |
这个是没有问题的,if并没有引入一个新的作用域,x仍处在当前作用域中,后面代码可以使用。
1 2 3 4 |
def test(): x2 = 2 print(x2) # NameError: name ‘x2’ is not defined |
def、class、lambda是可以引入新作用域的。
3、变量的修改
一个不在局部作用域里的变量默认是只读的,如果试图为其绑定一个新的值,python认为是在当前的局部作用域里创建一个新的变量,也就是说在当前局部作用域中,如果直接使用外部作用域的变量,那么这个变量是只读的,不能修改,如:
1 2 3 4 5 6 7 |
count = 10 def outer(): print(count) count = 100 print(count) outer() #UnboundLocalError: local variable ‘count’ referenced before assignment |
这里第一个print中,使用到了外部作用域的count,这样后面count就指外部作用域中的count了,再修改就会报错。 如果没使用过这个变量,而直接赋值,会认为是新定义的变量,此时会覆盖外部作用域中变量,如:
1 2 3 4 5 6 |
count = 10 def outer(): count = 100 print(count) outer() #100 |
内部作用域中直接声明了count=100,后面使用count都是内部作用域的了。
4、global关键字
当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了,当修改的变量是在全局作用域(global作用域)上的,就要使用global先声明一下,代码如下:
1 2 3 4 5 6 7 8 9 |
count = 10 def outer(): global count print(count) count = 100 print(count) outer() #10 #100 |
5、nonlocal关键字
global关键字声明的变量必须在全局作用域上,不能嵌套作用域上,当要修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量怎么办呢,这时就需要nonlocal关键字了
1 2 3 4 5 6 7 8 9 10 11 |
def outer(): count = 10 def inner(): nonlocal count count = 20 print(count) inner() print(count) outer() #20 #20 |
6、小结
(1)变量查找顺序:LEGB,作用域局部>外层作用域>当前模块中的全局>python内置作用域; (2)只有模块、类、及函数才能引入新作用域; (3)对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量; (4)内部作用域要修改外部作用域变量的值时,全局变量要使用global关键字,嵌套作用域变量要使用nonlocal关键字。nonlocal是python3新增的关键字,有了这个关键字,就能完美的实现闭包了。
#!/usr/bin/python
# -*- coding: utf-8 -*-
“””
——————————————————————————-
Function:
【整理】Python中:self和init__的含义 + 为何要有self和__init__
http://www.crifan.com/summary_the_meaning_of_self_and___init___in_python_and_why_need_them
Author: Crifan
Verison: 2012-11-27
——————————————————————————-
“””
#注:此处全局的变量名,写成name,只是为了演示而用
#实际上,好的编程风格,应该写成gName之类的名字,以表示该变量是Global的变量
name = “whole global name”;
class Person:
name = “class global name”
def __init__(self, newPersionName):
#self.name = newPersionName;
#此处,没有使用self.name
#而使得此处的name,实际上仍是局部变量name
#虽然此处赋值了,但是后面没有被利用到,属于被浪费了的局部变量name
name = newPersionName;
def sayYourName(self):
#此处,之所以没有像之前一样出现:
#AttributeError: Person instance has no attribute ‘name’
#那是因为,虽然当前的实例self中,没有在__init__中初始化对应的name变量,实例self中没有对应的name变量
#但是由于实例所对应的类Person,有对应的name变量,所以也是可以正常执行代码的
#对应的,此处的self.name,实际上是Person.name
print(‘My name is %s’%(self.name)); # -> class global name
print(‘name within class Person is actually the global name: %s’%(name)); #-> whole global name
print(“only access Person’s name via Person.name=%s”%(Person.name)); # -> class global name
def selfAndInitDemo():
persionInstance = Person(“crifan”);
persionInstance.sayYourName();
print(“whole global name is %s”%(name)); # -> whole global name
###############################################################################
if __name__==”__main__”:
selfAndInitDemo();