函数

三、作用域规则

有了函数之后,我们必须要面对一个作用域的问题。

比如:你现在访问一个变量,那么 python 解析器是怎么查找到这个变量,并读取到这个变量的值的呢? 依靠的就是作用域规则!

3.1 作用域

作用域(scope)

作用域就是 python 程序的一块文本区域,在这个区域内,可以直接访问(Directly accessible)命名空间。

直接访问的意思就是:当你访问一个绝对的命名的时候,直接在命名空间中查找

尽管作用域的定义是静态的,但是作用域的使用(查找变量)却是动态的。


在代码执行的任何时间,至少有 3 个嵌套的作用域,这些作用域的命名空间可以直接访问。

  1. 内部作用域(局部作用域)。包含了所有的局部命名,在访问变量的时候,首先在内部作用域中查找。
  2. 然后是嵌套函数的外层作用域。在这里搜索非局部,但也是非全局的命名。(在 python 中允许在函数中定义函数的)
  3. 然后是包含当前模块的全局作用域。
  4. 最后搜索的是最外层的创建内置命名的作用域。

作用域搜索规则:LEGB

L:局部的(local)

E:封闭的(Enclosing)

G:全局的(Global)

B:内置的(Built-in)

一、局部命名空间

函数内部的命名空间,在调用函数的时候生成,调用结束时消失。当局部命名空间有效时,它是第一个用于检查某个名字存在性的命名空间。如果在局部命名空间内找到该名称,则返回与名字相关联的对象,反之提示出错。

3.2作用域在 python 中的具体应用

3.2.1.访问局部作用域

def foo():
a = 20
print(a) foo()

说明:

函数内部访问变量a, 先在foo函数内部查找。因为 a确实是在函数内部声明的变量,然后就找到了a


3.2.2.访问外部作用域

a = 100

def foo():
print(a) foo()

说明:

  1. foo函数内部,我们直接去访问一个变量 a,那么就会沿着作用域从内向外开始查找a
  2. 先查找foo的局部作用域,发现没有a。然后继续去foo函数的外部作用域,这个例子中就直接到了当前模块的全局作用域,所以找到了 a, 所以就输出了全局作用域中a的值!

3.2.3.访问外部函数的作用域

def outer():
a = 20 def inner():
print(a) inner() outer()

说明:

  1. 我们在一个函数的内部声明了一函数,这种函数嵌套在 python 中是允许的。
  2. 内部函数inner执行的时候,访问变量a,现在inner内部找变量a, 没有找到,然后去他外部的函数中找变量a, 找到后, 就直接输出了他的值

3.2.4 python 针对修改变量值的特殊情况

3.2.4.1.只能修改局部变量

在 python 的函数中, 修改一个变量的值的时候,永远操作的是局部变量

为什么会这样呢?

这其实是由 python 定义变量的方式所决定的.

python 不需要显示的去定义变量,直接赋值的时候如果变量不存在直接就定义了.

如果在函数内部可以直接修改外部作用域变量的值,则就无法定义一个同名变量了.

所以, python 才规定不能在函数内部直接修改外部作用域变量的值.


a = 10

def foo():
a = 20 # 这里其实是新创建了一个局部变量 a .并不是修改的全局作用域的变量 a print(a) # 根据作用域的查找规则,这里访问的是局部变量 a foo()
print(a) # 根据作用域查找规则,这里访问的是全局作用域的 a


3.2.4.2.变量必须先赋值才能使用

看下面的代码:

a = 10

def foo():
a = a + 2 foo()

说明:

a = a + 2 这行代码有问题. 为什么?

首先要搞清楚 a + 2 中的a是局部变量还是全局变量?

是局部变量a!

在解释器运行这个函数的时候, 已经检测到函数内部有创建局部变量a, 所以这个时候你访问到的一定是局部变量a.

a + 2 中的局部变量a还没有 被赋值,所以和 2 相加抛出了异常.UnboundLocalError(局部变量错误)


a = 10

def foo():
print(a)
a = 20 foo()

说明:

原因和前面的一样的.

解析器已经检测到你后面会声明局部变量a, 所以print(a)中的 a 仍然是局部变量.但是还没有赋值,所以就抛异常了


总结:

在函数内部如果你定义了局部变量,那么你在任何地方都没有办法访问到函数外部作用域的同名变量.


3.2.4.3 函数内修改全局变量

通过前面的学习, 正常情况下我们知道了在函数内部没有办法修改全局变量的值!

但是这只是正常情况下!

如果我们有在函数内部修改全局变量值的需求怎么办?

也是可以的, 但是我们需要做些小动作: 使用关键字global


a = 10

def foo():
global a # 告诉 python 解析器, a 以后就是全局变量了
a = 20 foo() print(a) # 20

说明:

  1. global 后面跟上全局变量的名, 那么在后面的代码中就可以使用全局变量了.
  2. 如果有多个全局变量需要修改, global可以同时定义多个全局变量.global a, b, c

3.2.4.4内部函数修改外部函数的局部变量

当用到函数嵌套的时候, 内部函数正常情况下也是无法修改外部函数的局部变量, 只能访问读取.

如果想修改怎么办?

使用关键字:nonlocal

a = 10

def outer():
a = 20 def inner():
nonlocal a # 把 a 绑定到外部函数的局部变量 a 上
a = 30 inner() print("outer 的局部变量a:" + str(a)) # 30 被内部函数 inner 修改了 outer()
#print("全局变量a:%d"%a)
#print("全局变量a:",a)
print("全局变量a:" + str(a))

Python第六章-函数02-函数的作用域的更多相关文章

  1. Python函数02/函数的动态参数/函数的注释/名称空间/函数的嵌套/global以及nolocal的用法

    Python函数02/函数的动态参数/函数的注释/名称空间/函数的嵌套/global以及nolocal的用法 目录 Python函数02/函数的动态参数/函数的注释/名称空间/函数的嵌套/global ...

  2. 简学Python第六章__class面向对象编程与异常处理

    Python第六章__class面向对象编程与异常处理 欢迎加入Linux_Python学习群  群号:478616847 目录: 面向对象的程序设计 类和对象 封装 继承与派生 多态与多态性 特性p ...

  3. “全栈2019”Java异常第六章:finally代码块作用域详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  4. Python第六章-函数01-函数的概念和使用

    函数 为了便于程序的维护和更好的实现模块化,好的程序都会分解为很多函数. 可以这么说,对于任何的编程语言,函数都是一个非常重要的概念. python 不仅简化了函数的定义过程,而且还大量借鉴了其他函数 ...

  5. Python第六章-函数06-高阶函数

    函数的高级应用 二.高阶函数 高级函数, 英文叫 Higher-order Function. 那么什么是高阶函数呢? 在说明什么是=高阶函数之前, 我们需要对函数再做进一步的理解! 2.1 函数的本 ...

  6. Python第六章 面向对象

    第六章 面向对象 1.面向对象初了解 ​ 面向对象的优点: ​ 1.对相似功能的函数,同一个业务下的函数进行归类,分类 ​ 2.类是一个公共的模板,对象就是从具体的模板中实例化出来的,得到对象就得到一 ...

  7. Python第六章-函数04-递归函数和拉姆达表达式

    五.递归函数 什么叫递归(recusive)? 你拿两个镜子互相面对着, 然后去看镜子, 会发现每个镜子中很多个镜子, 层层的嵌套, 无穷尽, 这就是一种递归! 从前有坐山, 山里有座庙, 庙里有个老 ...

  8. Python第六章-函数05-迭代器&生成器

    python作为一个既面向对象,又支持函数式编程的语言,函数的使用方面有很多特点. 比如:闭包,装饰器,迭代器等 函数的高级应用 容器:生活中常见的容器有哪些?袋子,盆子,水杯,书包,铅笔盒... 容 ...

  9. python3 第二十六章 - 内置函数之Number相关

    数学函数 函数 返回值 ( 描述 ) 实例 abs(x) 返回数字的绝对值,如abs(-10) 返回 10 print(abs(-10)) =======输出:====== 10 ceil(x) 返回 ...

随机推荐

  1. toString和valueOf

    toString 今天在看以前写的代码时,遇到某个老师的点评: var obj = {};var root = [1, 2, 3];obj[root.join(',')] = value; 一看到这个 ...

  2. songCMS 3.15 cookie SQLINJ

    ./code/profile.php ... $db = new db(); $SQL = "SELECT * FROM `{$dbprefix}user` WHERE `ID` = {$_ ...

  3. 在Docker中运行gocd

    gocd是一个持续集成的工具,可视化效果非常好 运行gocd-server 12345 docker run -d --name server -p8153:8153 -p8154:8154 -v / ...

  4. js操作复选框

    js操作复选框 JavaScript 代码: //复选框全选 $(function () { $("#select_all").click(function () { $(&quo ...

  5. iNeuOS工业互联平台,.NETCore开发的视频服务组件iNeuVideo,RTSP转WebSocket

    目       录 1.      概述... 2 2.      将来集成到iNeuOS平台演示... 3 3.      iNeuVideo结构... 3 4.      iNeuVideo部署及 ...

  6. ado.net DataSet

    一.概念 DataSet是ADO.NET的中心概念.可以把DataSet当成内存中的数据库,DataSet是不依赖于数据库的独立数据集合.所谓独立,就是说,即使断开数据链路,或者关闭数据库,DataS ...

  7. 【读书笔记】https://source.android.google.cn/compatibility/tests?hl=en

    AuthorBlog:秋城https://www.cnblogs.com/houser0323/ Android Platform Testing This content is geared tow ...

  8. 零基础HTML及CSS编码总结

    任务目的 针对设计稿样式进行合理的HTML架构,包括以下但不限于: * 掌握常用HTML标签的含义.用法 能够基于设计稿来合理规划HTML文档结构 理解语义化,合理地使用HTML标签来构建页面 掌握基 ...

  9. Python——工厂模式

    目录 前言 一.简单工厂 二.工厂方法 抽象工厂 结论 参考 前言 工厂模式,顾名思义就是我们可以通过一个指定的"工厂"获得需要的"产品". 在设计模式中主要用 ...

  10. 微信小程序结构目录、配置介绍、视图层(数据绑定,运算,列表渲染,条件渲染)

    目录 一.小程序结构目录 1.1 小程序文件结构和传统web对比 1.2 基本的项目目录 二.配置介绍 2.1 配置介绍 2.2 全局配置app.json 2.3 page.json 三.视图层 3. ...