6段代码带你了解python global变量

借4个例子(现在扩到六个了<( ̄︶ ̄)>),说明一下global的作用。

a=6
print(id(a))
def f():
    
    print(a)
    print(id(a))
f()
print(id(a))
print('finally:',a)

这个代码能跑通,强行理解就是f内强行找了外部的a=6,使用变量a。但是如果只是简单的找外部声明,下边的例子按理说也能跑通!

a=6
print(id(a))
def f():
    print(a)
    a = 2#wrong position
    print(id(a))
f()
print(id(a))
print('finally:',a)

但是实际上这段代码会报错,因为他没去外部找那个a=6,为什么没去,被a=2挡住了,尽管a=2在后边。还是能“未卜先知”!

python是一层一层按LEGB规则向外查询变量的声明的。回到前边那段成功的代码,唯一的区别就是查询过程没有a=2的阻挡。f内,print(a)前方并没有a的声明,但是a并没有直接在外部找到a=6,而是发现了print后方的a=2,所以按a=2来看,但是执行起来,a=2又在print(a)之后,所以,a就被“未声明”了!!!有点绕,简单说,就是需要找变量的时候,找变量范围这个动作是个不依赖代码顺序的独立过程,他是脱离位置关系的,但是找完了变量声明,执行的时候,还要自上而下逐行执行!


a=6
print(id(a))
def f():
    a= 2#right position!!!!!!!!
    print(a)
    print(id(a))
f()
print(id(a))
print('finally:',a)

改了顺序,就能执行通了。

但是前边墨迹了那么多,你想知道的,一定不是改一下顺序,规矩的执行下去,这个随便一个傻子也能摸索着办到。这种答案也不是本文的最终目的。本文最终代码如下,加global声明,位置随意,刚才说了,查询声明是脱离位置关系的,所以可以这样声明。这也是global关键字的意义。

a=6
print(id(a))
def f():
    print(a)
    global a#wrong position
    print(id(a))
f()
print(id(a))
print('finally:',a)

虽然这句声明删了也能默认产生这种效果(demo 1),能跑通,但是意义不明,也不能避免人为错误,默认使用规则也很抽象:只引用a就是全局,想修改(其实是声明)a就是局部(这都是python声明与赋值操作一体化的坑,用类和对象就不会这么抽象了,最起码你知道自己在声明对象,而不是在赋值和修改)。写了这句意义就明确了,使用的、和修改的,也都是同一个全局变量。

扩展证明一下:既有global声明又有赋值操作,且赋值操作在声明前边

下边代码:先赋值a,再声明global a,这时候a确实算global了,运行f()之后的全局的a也确实被替换了,id变了,数值也是3,这和前例不一样,前例只是声明的话,id都是不变的!id改变,也证明了a是global的,证明了global声明还是优先于a赋值操作的(原因见id测试demo5.2)。

#demo5
#assign before global declare
a = 6
print('id:',id(a))
def f():
    a = 3
    print('in function f() ',a)
    print('id:',id(a))
    global a
    #a = 5#another a
    print(a)
    print('id:',id(a))#another a
f()
print('after f():',a)
print(id(a))

另外,这里声明a=5的话,还会出一个新的id,覆盖之前的a=3的对象,仍然是一个global的对象,覆盖全局的a。(有没有global都是如此,每次新的“赋值”实质都是声明,python机制如此)

#demo5
#assign before global declare
a = 6
print('id:',id(a))
def f():
    a = 3
    print('in function f() ',a)
    print('id:',id(a))
    global a
    a = 5#another a
    print(a)
    print('id:',id(a))#another a
f()
print('after f():',a)
print(id(a))
-------------------------------------------------
C:/numpy_demo/python_demo/global_declare.py:64: SyntaxWarning: name 'a' is assigned to before global declaration
  global a
id: 1451579744
in function f()  3
id: 1451579696
5
ID: 1451579728
after f(): 5
1451579728
#demo5.2
a = 6
print('value is ',a, ' id is ',id(a))
a = 5
print('value is ',a, ' id is ',id(a))
a = 4
print('value is ',a, ' id is ',id(a))
a += 3
print('value is ',a, ' id is ',id(a))
--------------------------------------------
value is  6  id is  1451579744
value is  5  id is  1451579728
value is  4  id is  1451579712
value is  7  id is  1451579760

加一个对照组回归一下:不加global,运行f()之后,a仍然是6,id也没变。

证明前例那个global是有影响到global声明之前的a赋值操作的,这个global声明直接使a变成了全局对象。

#demo6
#just assign in local

a = 6
print('id:',id(a))
def f():
    a = 3
    print('in function f() ',a)
    print('id:',id(a))
    #global a
    a = 5#another a
    print(a)
    print('id:',id(a))#another a
f()
print('after f():',a)
print(id(a))
---------------------------
id: 1451579744
in function f()  3
id: 1451579696
5
ID: 1451579728
after f(): 6
1451579744

git链接

猜你喜欢

转载自blog.csdn.net/huqinweI987/article/details/82833716