一般来说,作为常量放在文件最开头,或者最外面的变量,是属于全局变量(静态变量),一般最好不要轻易改动他的取值,不管是在函数里,还是在主程序中。

其实python里面,什么东西都是涉及到命名域/作用域的,当然很多时候是隐式的给出的。实际上你可以通过把握三点来解决,不可变(传值)/可变对象(传引用),重新绑定(针对于可变对象的特殊情况)。或者可以说,python传递的是对象的引用。

其实如果不使用关键字global,函数也是可以改变全局变量的。请看下面的例子。

a=[1,2,3]
def add(x):
    a.append(100)
    a[0]=1000
    return x

print(add(a))
print(a)

输出:

global必须 python python中global()_global必须 python

a=[1,2,3]
def add(x):
    x+=[100]
    #注意不能使用x=x+[100],这在python里面是叫做重新绑定
    return x

print(add(a))
print(a) 
输出:

global必须 python python中global()_作用域_02

a=[1,2,3]
def add(x):
    a.append(100)
    return x

print(add(a))
print(a)

global必须 python python中global()_全局变量_03

但是上面的例子是可变对象list,但如果是不可变对象,那么它根本就没有那些原地改变的方法,也就不可能在函数里面改变,从而改变外部的全局变量,或者说它永远都对应着重新绑定(不改变原值)。详见下面例子。

a=100
#字符串,元组也一样
def add(x):
    x=1000
    return x

print(add(a))
print(a)

global必须 python python中global()_python_04

a=100
#字符串,元组也一样
def add(x):
    a=1000
    return x

print(add(a))
print(a)

global必须 python python中global()_global必须 python_05


这里的话,其实又可以延伸出另外一个知识点,python变量引用,以及重新赋值(或者叫绑定,该变量引用另外一个对象)的问题。关于这点网上其实有很介绍,python到底是传值还是传引用。但这里我想强调的重点是,对于重新绑定,就算是在函数里面对一个可变的全局变量(之前已绑定一个可变对象)进行重新绑定,它也不会对最终的全局变量造成影响。详见下面的例子。

a=[1,2,3]
def add(x):
    a=[100,200,300]
    return x

print(add(a))
print(a)

global必须 python python中global()_python_06

a=[1,2,3]
def add(x):
    x=[100,200,300]
    return x

print(add(a))
print(a)

global必须 python python中global()_global必须 python_07


其实这里不管是函数(函数也是一种特殊的类对象),python一切皆对象嘛。。上面的这些,从广义上面来讲,都可以用命名空间来解释,python中其实都是传递引用的,只是在不同命名空间会造成联系,或者屏蔽。。

那么如果我实在是想在函数里面修改全局变量呢,该如何做,这个时候global关键字就发挥作用了,就算是重新绑定(不论是可变或者不可变对象),它也会及时生效。。

num = 1
def fun():

     num = 123
     print(num)

fun()
print(num)

此时没有使用global关键字,无法对全局变量num进行修改,运行结果如下:

global必须 python python中global()_作用域_08

想要对全局变量进行修改,要用到关键字global!

#global关键字(内部作用域想要对外部作用域的变量进行修改)
num = 1
def fun():
     global num
     num = 123
     print(num)

fun()
print(num)

运行结果如下:

global必须 python python中global()_作用域_09

注意:如果一个函数申明了global变量,如果一次执行中被多次调用,那么都是指这个全局变量,非常具有混乱性,是有历史的,类似于空列表作为函数默认参数的效果。

上面的关键字global,要先申明是全局的某个变量,再使用重新绑定。程序文件最开头的全局变量默认都是全局类型的,可加也可以不加global关键字。

其实python对这个引用以及作用域的设计很不严格,跟其他语言中也很不一样,具体情况具体分析,其次编译过程(一切皆对象,函数编译也会有记录)与调用执行过程可以是相互作用的,不同的,参考这里的一个例子以及之前默认值可变对象调用自动加1的例子。

a=[1,2,3]

def add(a):
    
    a=a+[100]
    b=a
    print(id(a))
    return b


print(add(a))
print(id(a))
print(a)

a=[1,2,3]

def add(a):
    
    a.append(100)
    b=a
    print(id(a))
    return b


print(add(a))
print(id(a))
print(a)


a=[1,2,3]

def add(a):
    
    a+=[100]
    b=a
    print(id(a))
    return b


print(add(a))
print(id(a))
print(a)


a=[1,2,3]

def add(a):
    
    a+=[100]
    b=a
    return b


print(add(a))
print(a)

a=[1,2,3]

def add(a):
    
    a=a+[100]
    b=a
    return b


print(add(a))
print(a)

a=[1,2,3]

def add(a):
    
    a=a.append(100)
    b=a
    return b


print(add(a))
print(a)

a=[1,2,3]

def add(a):
    b=a
    a=a.append(100)
    return b


print(add(a))
print(a)

a=[1,2,3]

def add():
    b=a
    a=a.append(100)
    return b


print(add())
print(a)

a=[1,2,3]

def add():
    b=a
    a=a+[100]
    return b


print(add())
print(a)


a=[1,2,3]

def add():
    b=a
    a+=[100]
    return b


print(add())
print(a)

a=[1,2,3]

def add():
    
    a+=[100]
    b=a
    return b


print(add())
print(a)

全局变量局部变量在编译期间就已经决定,在同一个作用域不能有模棱两可的定义,否则编译就会报错,其次同一内存,同一变量,还会有在不同作用域内以及不同的变量指向它,如果是可变对象,还是可以直接修改的(毕竟都是引用),或者强行用global申明,要具体情况具体分析,灵活应用,一般来说还是使用一般操作就好,不要花里胡哨。

其实最后几个例子还是很神奇的,这就是编译器的作用,直接阻止运行,在编译期间会直接设定全局,局部变量,设定好作用域,在调用时有违反直接报错(未定义变量),尽管可能某些情况下,局部变量与全局变量地址一样,但是内部已经解绑,属于不同作用域(虽然有时可以通过可变对象的属性进行原地修改,+=也是原地修改,但是已经解绑,区分了局部变量与全局变量,也就是作用域,不定义的局部变量直接使用必定报错,所以仍然要满足定义与调用一致的条件),这是最基本的,其次才是可变与不可变对象的引用关系(不同作用域可能共享一个变量地址)。如果想不报错,直接使用全局作用域,就需要告诉编译器信息了,也就是global关键字的作用,强行改变,不过这是不推荐的,写代码还是要遵守一下规范,保持良好的习惯以及清晰易懂的风格