在我接触过的编程语言中,一般对于变量会有两种作用域:全局(global)和局部(local),针对python的变量作用域,有以下几种:
L (Local) 局部作用域 E (Enclosing) 闭包函数外的函数中 G (Global) 全局作用域 B (Built-in) 内建作用域以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。
什么时候会产生作用域?
一般情况下当我们引入新的模块(module),类(class)以及函数(def、lambda)的时候就会产生作用域,因为以上三个概念中都包含自己的属性方法,这些属性和方法有自己存在的上下文环境(作用域)。 代码块(如if、try、for等)不会产生作用域
函数内部的变量名如果是第一次出现, 且在=符号前,那么就可以认为是被定义为局部变量。在这种情况下,不论全局变量中是否用到该变量名,函数中使用的都是局部变量。
由下图我们可以清楚的看到,即使函数外部定义了相同名称的变量,但是函数内部使用的还是在自己函数块中定义的局部变量,如果在函数块中未定义而想要使用函数块外部的函数就会报错:
UnboundLocalError: local variable 'age' referenced before assignment 提示错误:局部变量num在赋值前被应用。也就是说该变量没有定义就被错误使用。由此再次证明这里定义的是一个局部变量,而不是全局变量。函数内部的变量名如果是第一次出现,且出现在=符号后面,且在之前已被定义为全局变量,则这里将引用全局变量
age = 18 def changeage(): ageAdd = age + 5 print(ageAdd) changeage()运行结果:23 注意:函数中使用某个变量时,如果该变量名既有全局变量也有局部变量,则默认使用局部变量。
在函数中如果想要修改全局变量的值,则需要明确指出想要修改的值是一个全局变量,否则就会报变量未定义错误(因为默认会当做局部变量来处理)。指明格式为:
global variable示例:
age = 18 def changeage(): global age age += 5 print(age) changeage()运行结果:23
如果在一个内部函数里,对在外部函数内(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)
如果对于外部函数中的变量的引用在赋值之前,就会报错:
UnboundLocalError: local variable 'name' referenced before assignmentPython3有个关键字nonlocal可以解决这个问题,但在Python2中还是不要尝试修改闭包中的变量 注意:如果内部函数中未定义与外部变量同名的变量,则可以使用,这是因为变量检测的顺序,如果内部定义了,但是定义是在调用之后就会报错,如果内部没定义,那么就会在外部函数中寻找此变量。
locals() 和 globals()
globals() global 和 globals() 是不同的,global 是关键字用来声明一个局部变量为全局变量。globals() 和 locals() 提供了基于字典的访问全局和局部变量的方式
locals()
如果你使用过Python的Web框架,那么你一定经历过需要把一个视图函数内很多的局部变量传递给模板引擎,然后作用在HTML上。虽然你可以有一些更聪明的做法,还你是仍想一次传递很多变量。先不用了解这些语法是怎么来的,用做什么,只需要大致了解locals()是什么。可以看到,locals()把局部变量都给打包一起扔去了。
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())大家可以做一个笔试题来练习下:
给定一个正整数,编写程序计算有多少对质数的和等于输入的这个正整数,并输出结果。输入值小于1000。
#示例代码 def countCom(): counts = 0 n = input('Please input max number of list: ') def is_prime(n): if n == 1: return False for i in range(2, int(sqrt(n))+1): if n % i == 0: return False return True def recur(arg): nonlocal counts #############################注意上一行 for j in range(arg,int(n)+1): if arg+j == int(n) and is_prime(j) == True: counts = counts + 1 else: pass ntoNumber = int(n) for i in range(1,ntoNumber+1): if is_prime(i) == True and i >= 3: lst = [] lst.append(i) recur(i) print(counts)