网络编程
位置:首页>> 网络编程>> Python编程>> 深入了解Python 变量作用域

深入了解Python 变量作用域

作者:看云  发布时间:2023-06-08 10:01:15 

标签:Python,变量,作用域

特点

python的作用域是静态的,在源代码中变量名被赋值的位置决定了该变量能被访问的范围。即Python变量的作用域由变量所在源代码中的位置决定。Python中并不是所有的语句块中都会产生作用域。只有当变量在Module(模块)、Class(类)、def(函数)中定义的时候,才会有作用域的概念。

1. 函数内部的变量,函数外部不能访问


def func():
 variable = 100
 print(variable)
print(variable) # name 'variable' is not defined

2. 函数上层的变量(标量)只能读取,不能再次定义,初始化


def counter1():
 n = 0
 def compute():
   n = n + 1 # n为标量(数值,字符串,浮点数),Python程序会因为“如果内部函数有引用外部函数的同名变量或者全局变量,并且对这个变量有修改.那么python会认为它是一个局部变量,又因为函数中没有n的定义和赋值,所以报错
   # y = n + 1 # 更改为y就没事
   # return y
   return n
 return compute

variable = 300
def test_scopt():
 print(variable) # 此时调用局部变量variable并有没绑定到一个内存对象(没有定义和初始化,即没有赋值)。本质上还是遵循的LEGB法则
 variable = 200 #因为这里,前面调用过一次,所以variable就变为了局部变量
 # print(variable) # 写在下面就没问题,因为variable是新的局部变量,而不是重新被定义,却没有绑定
test_scopt()

Python中的模块代码在执行之前,并不会经过预编译,但是模块内的函数体代码在运行前会经过预编译,因此不管变量名的绑定发生在作用域的那个位置,都能被编译器知道。Python虽然是一个静态作用域语言,但变量名查找是动态发生的,直到在程序运行时,才会发现作用域方面的问题,

3. list,dict等复合变量里面的值都可以引用更改


def counter():
 n = [0]
 def compute():
   n[0] += 1 # 更改的是n里面的第一个值,不是更改n
   return n[0]
 return compute

func = counter()
func() # 1
func() # 2
func() # 3

4. global 声明全局变量,如果在局部要对全局变量修改,需要在局部也要先声明该全局变量


def counter1():
 n = 0
 def compute():
   global n # 如果在局部要对全局变量修改,需要在局部也要先声明该全局变量,但此处也会报错,因为没有全局变量n
   n += 1
   return n
 return compute

# right
def counter1():
 global n
 n = 0
 def compute():
   global n
   n += 1
   return n
 return compute

5. nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量


def make_counter():
 count = 0
 def counter():
   nonlocal count # 使用外层非全局变量
   count += 1
   return count
 return counter

作用域的类型

在Python中,使用一个变量时并不严格要求需要预先声明它,但是在真正使用它之前,它必须被绑定到某个内存对象(被定义、赋值);这种变量名的绑定将在当前作用域中引入新的变量,同时屏蔽外层作用域中的同名变量。

L(local)局部作用域

局部变量:包含在def关键字定义的语句块中,即在函数中定义的变量。每当函数被调用时都会创建一个新的局部作用域。Python中也有递归,即自己调用自己,每次调用都会创建一个新的局部命名空间。在函数内部的变量声明,除非特别的声明为全局变量,否则均默认为局部变量。有些情况需要在函数内部定义全局变量,这时可以使用global关键字来声明变量的作用域为全局。局部变量域就像一个 栈,仅仅是暂时的存在,依赖创建该局部作用域的函数是否处于活动的状态。所以,一般建议尽量少定义全局变量,因为全局变量在模块文件运行的过程中会一直存在,占用内存空间。
注意:如果需要在函数内部对全局变量赋值,需要在函数内部通过global语句声明该变量为全局变量。

E(enclosing)嵌套作用域

E也包含在def关键字中,E和L是相对的,E相对于更上层的函数而言也是L。与L的区别在于,对一个函数而言,L是定义在此函数内部的局部作用域,而E是定义在此函数的上一层父级函数的局部作用域。主要是为了实现Python的闭包,而增加的实现。

G(global)全局作用域

即在模块层次中定义的变量,每一个模块都是一个全局作用域。也就是说,在模块文件顶层声明的变量具有全局作用域,从外部开来,模块的全局变量就是一个模块对象的属性。
注意:全局作用域的作用范围仅限于单个模块文件内

B(built-in)内置作用域

系统内固定模块里定义的变量,如预定义在builtin 模块内的变量。

作用域链:变量名解析LEGB法则

搜索变量名的优先级:局部作用域 > 嵌套作用域 > 全局作用域 > 内置作用域
LEGB法则: 当在函数中使用未确定的变量名时,Python会按照优先级依次搜索4个作用域,以此来确定该变量名的意义。首先搜索局部作用域(L),之后是上一层嵌套结构中def或lambda函数的嵌套作用域(E),之后是全局作用域(G),最后是内置作用域(B)。按这个查找原则,在第一处找到的地方停止。如果没有找到,则会出发NameError错误。

example 1


name = "lzl"

def f1():
 print(name)

def f2():
 name = "eric"
 f1()

f2() # 在函数未执行之前,作用域链就已经形成了,此时f1()的上一级应该name = 'lzl'

example 2


def scope_test():
 def do_local():
   spam = "local spam" # 此函数定义了另外的一个spam字符串变量,并且生命周期只在此函数内。此处的spam和外层的spam是两个变量,如果写出spam = spam + “local spam” 会报错
 def do_nonlocal():
   nonlocal spam  # 使用外层的spam变量 test spam
   spam = "nonlocal spam"
 def do_global():
   global spam
   spam = "global spam"
 spam = "test spam"
 do_local()
 print("After local assignmanent:", spam) # test spam
 do_nonlocal()
 print("After nonlocal assignment:",spam) # nonlocal spam
 do_global()
 print("After global assignment:",spam) # nonlocal spam ???? 先找是本地变量,找到的本地变量已经在do_nonlocal()里面改变了所以输出的是nonlocal spam

scope_test()
print("In global scope:",spam) # global spam

来源:https://www.kancloud.cn/xiaoa/python-notes/1199059

0
投稿

猜你喜欢

  • 前言:Python中for循环和while循环本质上是没有区别的,但是在实际应用上,针对性不太一样。for循环,主要应用在遍历中,体现的是遍
  • 这篇论坛文章(赛迪网技术社区)主要介绍了数据仓库基本报表制作过程中的SQL写法,详细内容请参考下文:在数据仓库的基本报表制作过程中,通常会使
  • 这篇文章主要介绍了基于python3实现倒叙字符串,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可
  • 本文实例讲述了JavaScript点击按钮后弹出透明浮动层的方法。分享给大家供大家参考。具体分析如下:这里实现点击后页面变灰色,并用JS弹出
  • 函数javascript函数相信大家都写过不少了,所以我们这里只是简单介绍一下.创建函数:function f(x) {........}v
  • 如需安装运行环境或远程调试,可加QQ905733049, 或QQ2945218359由专业技术人员远程协助!运行结果如下:代码如下:impo
  • * 表的建立关系数据库的主要特点之一就是用表的方式组织数据。表是SQL语言存放数据、查找数据以及更新数据的基本数据结构。在SQL语言中,表有
  • 我们学习完推导式之后发现,推导式就是在容器中使用一个for循环而已,为什么没有元组推导式?原因就是“元组推导式&
  • 最近常有厦门的客户通过网站上的联系方式加我QQ,询问网站改版的情况。几乎每日都要针对客户网站存在的问题做一番分析,然后客户以价格等其他因素结
  • 动机一些bug由于本地环境和线上环境的不一致可能导致本地无法复现本地依赖和线上依赖版本不一致也可以导致一些问题有时一些bug跟数据相关,本地
  • 本文实例讲述了python 并发下载器实现方法。分享给大家供大家参考,具体如下:并发下载器并发下载原理from gevent import
  • 什么是 Goroutinegoroutine 是 Go 并行设计的核心。goroutine 说到底其实就是协程,它比线程更小,十几个 gor
  • spark编程python实例ValueError: Cannot run multiple SparkContexts at once;
  • 本文实例讲述了Python实现更改图片尺寸大小的方法。分享给大家供大家参考,具体如下:1、PIL包推荐Pillow 。2、源码:#encod
  • 本文描述通过统计分析出医院信息系统需分区的表,对需分区的表选择分区键,即找出包括在你的分区键中的列(表的属性),对大型数据的管理比较有意义,
  • 最近,某水果手机厂在万众期待中开了一场没有发布万众期待的手机产品的发布会,发布了除手机外的其他一些产品,也包括最新的水果14系统。几天后,更
  • 在使用SQL Server 的过程,中由于经常需要从多个不同地点将数据集中起来或向多个地点复制数据,所以数据的导出,导入是极为常见的操作.我
  • 1、单个关键字加亮代码: <div id="txt">  用JS让文章内容指定
  • 安装PIL在Debian/Ubuntu Linux下直接通过apt安装:$ sudo apt-get install python-imag
  • 这里使用TensorFlow实现一个简单的卷积神经网络,使用的是MNIST数据集。网络结构为:数据输入层–卷积层1–池化层1–卷积层2–池化
手机版 网络编程 asp之家 www.aspxhome.com