本篇文章小编给大家分享一下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

python 全局变量使用报错没有定义_Python变量作用域代码解析相关推荐

  1. python 全局变量使用报错没有定义_python跨文件使用全局变量的实现

    Python 定义了全局变量的特性,使用global 关键字修饰 global key_word 但是他的一大缺陷就是只能本module 中也就是本文件中使用,跳出这个module就不行. try 1 ...

  2. Python安装xlrd和xlwt的步骤以及使用报错的解决方法

    Python安装xlrd和xlwt的步骤以及使用报错的解决方法 参考文章: (1)Python安装xlrd和xlwt的步骤以及使用报错的解决方法 (2)https://www.cnblogs.com/ ...

  3. “this”不能在常量表达式中使用报错的解决方法

    "this"不能在常量表达式中使用报错的解决方法 问题描述与思考 在用C++书写下面一段代码时,编译器报错"'this'不能在常量表达式中使用".在这里,我最开 ...

  4. git使用报错:fatal: Couldn't find remote ref master的解决方法

    git使用报错:fatal: Couldn't find remote ref master的解决方法 fatal: Couldn't find remote ref master 翻译过来就是:致命 ...

  5. 记录webpack使用问题,使用报错“UnhandledPromiseRejectionWarning,file-loader图片过大,无法加载图片,打包html文件报错TypeError

    记录webpack使用报错 版本号问题 运行npm run build,报错 "UnhandledPromiseRejectionWarning: TypeError: this.getRe ...

  6. Assets.car 解压工具 cartool 使用报错 segmentation fault cartool 解决方案

    Assets.car 解压工具 cartool 使用报错 segmentation fault cartool 解决方案 参考文章: (1)Assets.car 解压工具 cartool 使用报错 s ...

  7. CentOS系统yum源使用报错:Error: Cannot retrieve repository metadata

    服务器上的yum突然不好使用,使用yum的时候报错如下: [root@bastion-IDC src]# yum list ...... Could not retrieve mirrorlist h ...

  8. git使用报错: fatal: Couldn‘t find remote ref master的解决方法

    git使用报错: fatal: Couldn't find remote ref master的解决方法 参考文章: (1)git使用报错: fatal: Couldn't find remote r ...

  9. cnpm使用报错-最佳方案

    问题:cnpm使用报错throw err;^Error: Cannot find module 'fs/promises 现象: 解决方案: 查看你的cnpm的版本是不是高于8.2.0 cnpm 8. ...

最新文章

  1. delphi 16 网页缩放
  2. 吉林大学c语言考试题库,吉林大学C语言题库.docx
  3. java servlet 多线程_java – 多线程GAE servlet来处理并发用户
  4. oracle 命令日志输出,ORACLE常用命令日志
  5. (剑指Offer)面试题4:替换空格
  6. mysql技术内幕sampdb_MySQL技术内幕汇总
  7. Mysql写入数据时,adapter 日志报ES连接错误
  8. mysql b tree索引原理_MySQL中B+Tree索引原理
  9. Luogu P4148 简单题(K-D Tree)
  10. Cglib动态代理实现原理
  11. 【转】只有运用你的逻辑才能看懂其中的恐怖
  12. 温控PLC三菱风机程序设计多路多路风机,温度控制,时间控制
  13. UFS 3.1协议分析(第一至四章) -- UFS概述
  14. PostgreSQL透明数据加密
  15. el-form 表单的校验
  16. Response to preflight request doesn‘t pass access control check: It does not have HTTP ok status.
  17. mysql limit 含义_深入分析Mysql中limit的用法
  18. 面试高薪程序员之高频面试题(一),集合,JVM,高并发多线程等
  19. 金融时间序列分析——对收益率序列平稳化处理
  20. krypt服务器支持voip嘛,Krypt.com

热门文章

  1. 2010年开年的一地鸡毛
  2. 瓦尔都窗前的一瞥 ①
  3. nodejs mysql模块_NodeJs使用Mysql模块实现事务处理
  4. PHP 框架 模块化,Laravel 的模块化开发框架 Notadd RC1
  5. react不同环境不同配置angular_叫雨山斗鸡优势在哪里,环境不同,价值不同
  6. arm tbh_TBH的完整形式是什么?
  7. 半素数c语言,非常简单的c题目 不懂 紧急求助
  8. sox处理mp3_使用SoX将mp3文件拆分为TIME秒
  9. android 模仿uc标签页,模仿UCweb菜单 - 白羽雕弓 - 博客园
  10. 怎么让模糊的数字变清楚_一键模糊图像变清晰,好家伙!这款神器插件你值得拥有...