首页 后端开发 Python教程 从局部变量和全局变量解析Python中变量的作用域

从局部变量和全局变量解析Python中变量的作用域

Mar 02, 2017 am 11:10 AM

无论是以类为基础的面相对象编程,还是单纯函数内部变量的定义,变量的作用域始终是Python学习中一个必须理解掌握的环节,下面我们从局部变量和全局变量开始全面解析Python中变量的作用域,需要的朋友可以参考下

理解全局变量和局部变量
1.定义的函数内部的变量名如果是第一次出现, 且在=符号前,那么就可以认为是被定义为局部变量。在这种情况下,不论全局变量中是否用到该变量名,函数中使用的都是局部变量。例如:

  num = 100
  def func():
    num = 123
    print num
  func()
登录后复制

输出结果是123。说明函数中定义的变量名num是一个局部变量,覆盖全局变量。再例如:

  num = 100
  def func():
    num += 100
    print num
  func()
登录后复制

输出结果是:UnboundLocalError: local variable 'num' referenced before assignment。提示错误:局部变量num在赋值前被应用。也就是说该变量没有定义就被错误使用。由此再次证明这里定义的是一个局部变量,而不是全局变量。

2.函数内部的变量名如果是第一次出现,且出现在=符号后面,且在之前已被定义为全局变量,则这里将引用全局变量。例如:

  num = 100
  def func():
    x = num + 100
    print x
  func()
登录后复制

输出结果是200。如果变量名num在之前没有被定义为全局变量,则会出现错误提示:变量没有定义。例如:

  def func():
    x = num + 100
    print x
  func()
登录后复制

输出结果是:NameError: global name 'num' is not defined。

3.函数中使用某个变量时,如果该变量名既有全局变量也有局部变量,则默认使用局部变量。例如:

  num = 100
  def func():
    num = 200
    x = num + 100
    prinx x
  func()
登录后复制

输出结果是300。

4.在函数中将某个变量定义为全局变量时需要使用关键字global。例如:

  num = 100
  def func():
    global num
    num = 200
    print num
  func()
  print num
登录后复制

输出结果分别是200和200。这说明函数中的变量名num被定义为全局变量,并被赋值为200。再例如:

  num = 100
  def func():
    global num
    num = 200
    num += 100
    print num
  func()
  print num
登录后复制

输出结果分别是300和300。

结合上文对全局变量和局部变量的应用场景的整理结果,我尝试对input fields中的教学代码的前半部分做一些分析(中文部分的注释):

  # calculator with all buttons

  import simplegui

  # intialize globals
  store = 0
  operand = 0
登录后复制

这里调用了simplegui模块,可以在http://www.php.cn/操作无误。但是该模块无法直接在python环境中使用,需要先安装SimpleGUICS2Pygame包。

  # event handlers for calculator with a store and operand

  def output():
  """prints contents of store and operand"""
    print "Store = ", store
    print "Operand = ", operand
    print ""
登录后复制

在定义的函数output()中直接使用了全局变量store和operand。可以参考第2点。

  def swap():
  """ swap contents of store and operand"""
    global store, operand
    store, operand = operand, store
    output()
登录后复制

在定义的函数swap()中首先对store和operand做了全局变量的定义。如果不这样操作,那么就会出现没有赋值就被使用的错误提示。可以参考第1点。同时是不是可以这样理解:函数swap()中,在没有关键字global的情况下,store和operand是默认局部变量,而=右边的部分在没有赋值的情况被使用是错误的。可以参考第3点。

  def add():
  """ add operand to store"""

    global store
    store = store + operand
    output()
登录后复制

在这里我碰到了两周课程学习以来的第一个难题:那就是为什么add()函数中只定义了store为全局变量,而没有相同地去定义operand。现在结合第1点来看,是因为store作为局部变量没有事先赋值,不能直接使用,而operand是可以直接调用之前定义的全局变量来使用的。

变量作用域
变量作用域(scope)在Python中是一个容易掉坑的地方。
Python的作用域一共有4中,分别是:

L (Local) 局部作用域
E (Enclosing) 闭包函数外的函数中
G (Global) 全局作用域
B (Built-in) 内建作用域
以 L --> E --> G -->B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。

Python除了def/class/lambda 外,其他如: if/elif/else/ try/except for/while并不能改变其作用域。定义在他们之内的变量,外部还是可以访问。

>>> if True:
...   a = 'I am A'
... 
>>> a
'I am A'
登录后复制

定义在if语言中的变量a,外部还是可以访问的。
但是需要注意如果if被 def/class/lambda 包裹,在内部赋值,就变成了此 函数/类/lambda 的局部作用域。
在 def/class/lambda内进行赋值,就变成了其局部的作用域,局部作用域会覆盖全局作用域,但不会影响全局作用域。

g = 1 #全局的
def fun():
  g = 2 #局部的
  return g

print fun()
# 结果为2
print g
# 结果为1
登录后复制

但是要注意,有时候想在函数内部引用全局的变量,疏忽了就会出现错误,比如:

#file1.py
var = 1
def fun():
  print var
  var = 200
print fun()

#file2.py
var = 1
def fun():
  var = var + 1
  return var
print fun()
登录后复制

这两个函数都会报错UnboundLocalError: local variable 'var' referenced before assignment
在未被赋值之前引用的错误!为什么?因为在函数的内部,解释器探测到var被重新赋值了,所以var成为了局部变量,但是在没有被赋值之前就想使用var,便会出现这个错误。解决的方法是在函数内部添加 globals var 但运行函数后全局的var也会被修改。

闭包Closure
闭包的定义:如果在一个内部函数里,对在外部函数内(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)

函数嵌套/闭包中的作用域:

a = 1
def external():
  global a
  a = 200
  print a

  b = 100
  def internal():
    # nonlocal b
    print b
    b = 200
    return b

  internal()
  print b

print external()
登录后复制

一样会报错- 引用在赋值之前,Python3有个关键字nonlocal可以解决这个问题,但在Python2中还是不要尝试修改闭包中的变量。 关于闭包中还有一个坑:

from functools import wraps

def wrapper(log):
  def external(F):
    @wraps(F)
    def internal(**kw):
      if False:
        log = 'modified'
      print log
    return internal
  return external

@wrapper('first')
def abc():
  pass

print abc()
登录后复制

也会出现 引用在赋值之前 的错误,原因是解释器探测到了 if False 中的重新赋值,所以不会去闭包的外部函数(Enclosing)中找变量,但 if Flase 不成立没有执行,所以便会出现此错误。除非你还需要else: log='var' 或者 if True 但这样添加逻辑语句就没了意义,所以尽量不要修改闭包中的变量。

好像用常规的方法无法让闭包实现计数器的功能,因为在内部进行 count +=1 便会出现 引用在赋值之前 的错误,解决办法:(或Py3环境下的 nonlocal 关键字)

def counter(start):
    count =[start]
    def internal():
      count[0] += 1
      return count[0]
    return internal

count = counter(0)
for n in range(10):
  print count()
# 1,2,3,4,5,6,7,8,9,10

count = counter(0)
print count()
# 1
登录后复制

由于 list 具有可变性,而字符串是不可变类型。

locals() 和 globals()
globals()
global 和 globals() 是不同的,global 是关键字用来声明一个局部变量为全局变量。globals() 和 locals() 提供了基于字典的访问全局和局部变量的方式

比如:如果函数1内需要定义一个局部变量,名字另一个函数2相同,但又要在函数1内引用这个函数2。

def var():
  pass

def f2():
  var = 'Just a String'
  f1 = globals()['var']
  print var
  return type(f1)

print f2()
# Just a String
# <type &#39;function&#39;>
登录后复制

locals()
如果你使用过Python的Web框架,那么你一定经历过需要把一个视图函数内很多的局部变量传递给模板引擎,然后作用在HTML上。虽然你可以有一些更聪明的做法,还你是仍想一次传递很多变量。先不用了解这些语法是怎么来的,用做什么,只需要大致了解locals()是什么。
可以看到,locals()把局部变量都给打包一起扔去了。

@app.route(&#39;/&#39;)
def view():
  user = User.query.all()
  article = Article.query.all()
  ip = request.environ.get(&#39;HTTP_X_REAL_IP&#39;,     request.remote_addr)
  s = &#39;Just a String&#39;
  return render_template(&#39;index.html&#39;, user=user,
      article = article, ip=ip, s=s)
  #或者 return render_template(&#39;index.html&#39;, **locals())
登录后复制

更多从局部变量和全局变量解析Python中变量的作用域相关文章请关注PHP中文网!


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何解决Linux终端中查看Python版本时遇到的权限问题? 如何解决Linux终端中查看Python版本时遇到的权限问题? Apr 01, 2025 pm 05:09 PM

Linux终端中查看Python版本时遇到权限问题的解决方法当你在Linux终端中尝试查看Python的版本时,输入python...

在Python中如何高效地将一个DataFrame的整列复制到另一个结构不同的DataFrame中? 在Python中如何高效地将一个DataFrame的整列复制到另一个结构不同的DataFrame中? Apr 01, 2025 pm 11:15 PM

在使用Python的pandas库时,如何在两个结构不同的DataFrame之间进行整列复制是一个常见的问题。假设我们有两个Dat...

哪些流行的Python库及其用途? 哪些流行的Python库及其用途? Mar 21, 2025 pm 06:46 PM

本文讨论了诸如Numpy,Pandas,Matplotlib,Scikit-Learn,Tensorflow,Tensorflow,Django,Blask和请求等流行的Python库,并详细介绍了它们在科学计算,数据分析,可视化,机器学习,网络开发和H中的用途

Uvicorn是如何在没有serve_forever()的情况下持续监听HTTP请求的? Uvicorn是如何在没有serve_forever()的情况下持续监听HTTP请求的? Apr 01, 2025 pm 10:51 PM

Uvicorn是如何持续监听HTTP请求的?Uvicorn是一个基于ASGI的轻量级Web服务器,其核心功能之一便是监听HTTP请求并进�...

Python中如何通过字符串动态创建对象并调用其方法? Python中如何通过字符串动态创建对象并调用其方法? Apr 01, 2025 pm 11:18 PM

在Python中,如何通过字符串动态创建对象并调用其方法?这是一个常见的编程需求,尤其在需要根据配置或运行...

如何在10小时内通过项目和问题驱动的方式教计算机小白编程基础? 如何在10小时内通过项目和问题驱动的方式教计算机小白编程基础? Apr 02, 2025 am 07:18 AM

如何在10小时内教计算机小白编程基础?如果你只有10个小时来教计算机小白一些编程知识,你会选择教些什么�...

什么是正则表达式? 什么是正则表达式? Mar 20, 2025 pm 06:25 PM

正则表达式是在编程中进行模式匹配和文本操作的强大工具,从而提高了各种应用程序的文本处理效率。

See all articles