变量作用于
讲到了函数就必须介绍变量的作用域相关。 作用域指的是变量的有效范围。变量并不是在哪个位置都可以访问的,访问权限取决于这个变量是在哪里赋值的,也就是在哪个作用域内的。 通常而言,在编程语言中,变量的作用域从代码结构形式来看,有块级、函数、类、模块、包等由小到大的级别。但是在Python中,没有块级作用域,也就是类似if语句块、for语句块、with上下文管理器等等是不存在作用域概念的,他们等同于普通的语句。 >>> if True: # if语句块没有作用域 x = 1 >>> x 1 >>> def func(): # 函数有作用域 a = 8 >>> a Traceback (most recent call last): File "<pyshell#3>",line 1,in <module> a NameError: name ‘a‘ is not defined 从上面的例子中,我们可以发现,在if语句内定义的变量x,可以被外部访问,而在函数func()中定义的变量a,则无法在外部访问。 通常,函数内部的变量无法被函数外部访问,但内部可以访问;类内部的变量无法被外部访问,但类的内部可以。通俗来讲,就是内部代码可以访问外部变量,而外部代码通常无法访问内部变量。 变量的作用域决定了程序的哪一部分可以访问哪个特定的变量名称。Python的作用域一共有4层,分别是:
x = int(2.9) # 内建作用域,查找int函数 global_var = 0 # 全局作用域 def outer(): out_var = 1 # 闭包函数外的函数中 def inner(): inner_var = 2 # 局部作用域 前面说的都是变量可以找得到的情况,那如果出现本身作用域没有定义的变量,那该如何寻找呢? Python以 a = 1 def func(): print(a) 全局变量和局部变量 定义在函数内部的变量拥有一个局部作用域,被叫做局部变量,定义在函数外的拥有全局作用域的变量,被称为全局变量。(类、模块等同理) 所谓的局部变量是相对的。局部变量也有可能是更小范围内的变量的外部变量。 局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中 a = 1 # 全局变量 def func(): b = 2 # 局部变量 print(a) # 可访问全局变量a,无法访问它内部的c def inner(): c = 3 # 更局部的变量 print(a) # 可以访问全局变量a print(b) # b对于inner函数来说,就是外部变量 print(c) global和nonlocal关键字 我们先看下面的例子: def plus(arg1,arg2): total = arg1 + arg2 # total在这里是局部变量. print("函数内局部变量total= ",total) print("函数内的total的内存地址是: ",id(total)) return total plus(10,20) print("函数外部全局变量total= ",total) print("函数外的total的内存地址是: ",id(total)) 很明显,函数plus内部通过 global:指定当前变量使用外部的全局变量 def plus(arg1,arg2): global total total = arg1 + arg2 # total在这里是局部变量. print("函数内局部变量total= ",id(total)) 打印结果是: 函数内局部变量total= 30 函数内的total的内存地址是: 1652778112 函数外部全局变量total= 30 函数外的total的内存地址是: 1652778112 我们再来看下面的例子: a = 1 print("函数outer调用之前全局变量a的内存地址: ",id(a)) def outer(): a = 2 print("函数outer调用之时闭包外部的变量a的内存地址: ",id(a)) def inner(): a = 3 print("函数inner调用之后闭包内部变量a的内存地址: ",id(a)) inner() print("函数inner调用之后,闭包外部的变量a的内存地址: ",id(a)) outer() print("函数outer执行完毕,全局变量a的内存地址: ",id(a)) 如果你将前面的知识点都理解通透了,那么这里应该没什么问题,三个a各是各的a,各自有不同的内存地址,是三个不同的变量。打印结果也很好的证明了这点: 函数outer调用之前全局变量a的内存地址: 1652777184 函数outer调用之时闭包外部的变量a的内存地址: 1652777216 函数inner调用之后闭包内部变量a的内存地址: 1652777248 函数inner调用之后,闭包外部的变量a的内存地址: 1652777216 函数outer执行完毕,全局变量a的内存地址: 1652777184 那么,如果,inner内部想使用outer里面的那个a,而不是全局变量的那个a,怎么办?用global关键字?先试试看吧: ? a = 1 print("函数outer调用之前全局变量a的内存地址: ",id(a)) def inner(): global a # 注意这行 a = 3 print("函数inner调用之后闭包内部变量a的内存地址: ",id(a)) 运行结果如下,很明显,global使用的是全局变量a。 函数outer调用之前全局变量a的内存地址: 1652777184 函数outer调用之时闭包外部的变量a的内存地址: 1652777216 函数inner调用之后闭包内部变量a的内存地址: 1652777248 函数inner调用之后,闭包外部的变量a的内存地址: 1652777216 函数outer执行完毕,全局变量a的内存地址: 1652777248 那怎么办呢?使用 函数outer调用之前全局变量a的内存地址: 1652777184 函数outer调用之时闭包外部的变量a的内存地址: 1652777216 函数inner调用之后闭包内部变量a的内存地址: 1652777248 函数inner调用之后,闭包外部的变量a的内存地址: 1652777248 函数outer执行完毕,全局变量a的内存地址: 1652777184 面试真题: 不要上机测试,请说出下面代码的运行结果: a = 10 def test(): a += 1 print(a) test()
更多的例子: 再来看一些例子(要注意其中的闭包,也就是函数内部封装了函数): name = ‘jack‘ def outer(): name=‘tom‘ def inner(): name =‘mary‘ print(name) inner() outer() 上面的题目很简单,因为inner函数本身有name变量,所以打印结果是mary。那么下面这个呢? name =‘jack‘ def f1(): print(name) def f2(): name = ‘eric‘ f1() f2() 这题有点迷惑性,想了半天,应该是‘eric’吧,因为f2函数调用的时候,在内部又调用了f1函数,f1自己没有name变量,那么就往外找,发现f2定义了个name,于是就打印这个name。错了!!!结果是‘jack’! Python函数的作用域取决于其函数代码块在整体代码中的位置,而不是调用时机的位置。调用f1的时候,会去f1函数的定义体查找,对于f1函数,它的外部是 再看下面的例子,f2函数返回了f1函数 name = ‘jack‘ def f2(): name = ‘eric‘ return f1 def f1(): print(name) ret = f2() ret() 仔细回想前面的例子,其实这里有异曲同工之妙,所以结果还是‘jack’。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |