Python第六章-函数02-函数的作用域
函数
三、作用域规则
有了函数之后,我们必须要面对一个作用域的问题。
比如:你现在访问一个变量,那么 python 解析器是怎么查找到这个变量,并读取到这个变量的值的呢? 依靠的就是作用域规则!
3.1 作用域
作用域(scope
)
作用域就是 python 程序的一块文本区域,在这个区域内,可以直接访问(Directly accessible)命名空间。
直接访问的意思就是:当你访问一个绝对的命名的时候,直接在命名空间中查找
尽管作用域的定义是静态的,但是作用域的使用(查找变量)却是动态的。
在代码执行的任何时间,至少有 3 个嵌套的作用域,这些作用域的命名空间可以直接访问。
- 内部作用域(局部作用域)。包含了所有的局部命名,在访问变量的时候,首先在内部作用域中查找。
- 然后是嵌套函数的外层作用域。在这里搜索非局部,但也是非全局的命名。(在 python 中允许在函数中定义函数的)
- 然后是包含当前模块的全局作用域。
- 最后搜索的是最外层的创建内置命名的作用域。
作用域搜索规则: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()
说明:
- 在
foo
函数内部,我们直接去访问一个变量a
,那么就会沿着作用域从内向外开始查找a
- 先查找
foo
的局部作用域,发现没有a
。然后继续去foo
函数的外部作用域,这个例子中就直接到了当前模块的全局作用域,所以找到了 a, 所以就输出了全局作用域中a
的值!
3.2.3.访问外部函数的作用域
def outer():
a = 20
def inner():
print(a)
inner()
outer()
说明:
- 我们在一个函数的内部声明了一函数,这种函数嵌套在 python 中是允许的。
- 内部函数
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
说明:
global
后面跟上全局变量的名, 那么在后面的代码中就可以使用全局变量了.- 如果有多个全局变量需要修改,
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-函数的作用域的更多相关文章
- Python函数02/函数的动态参数/函数的注释/名称空间/函数的嵌套/global以及nolocal的用法
Python函数02/函数的动态参数/函数的注释/名称空间/函数的嵌套/global以及nolocal的用法 目录 Python函数02/函数的动态参数/函数的注释/名称空间/函数的嵌套/global ...
- 简学Python第六章__class面向对象编程与异常处理
Python第六章__class面向对象编程与异常处理 欢迎加入Linux_Python学习群 群号:478616847 目录: 面向对象的程序设计 类和对象 封装 继承与派生 多态与多态性 特性p ...
- “全栈2019”Java异常第六章:finally代码块作用域详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- Python第六章-函数01-函数的概念和使用
函数 为了便于程序的维护和更好的实现模块化,好的程序都会分解为很多函数. 可以这么说,对于任何的编程语言,函数都是一个非常重要的概念. python 不仅简化了函数的定义过程,而且还大量借鉴了其他函数 ...
- Python第六章-函数06-高阶函数
函数的高级应用 二.高阶函数 高级函数, 英文叫 Higher-order Function. 那么什么是高阶函数呢? 在说明什么是=高阶函数之前, 我们需要对函数再做进一步的理解! 2.1 函数的本 ...
- Python第六章 面向对象
第六章 面向对象 1.面向对象初了解 面向对象的优点: 1.对相似功能的函数,同一个业务下的函数进行归类,分类 2.类是一个公共的模板,对象就是从具体的模板中实例化出来的,得到对象就得到一 ...
- Python第六章-函数04-递归函数和拉姆达表达式
五.递归函数 什么叫递归(recusive)? 你拿两个镜子互相面对着, 然后去看镜子, 会发现每个镜子中很多个镜子, 层层的嵌套, 无穷尽, 这就是一种递归! 从前有坐山, 山里有座庙, 庙里有个老 ...
- Python第六章-函数05-迭代器&生成器
python作为一个既面向对象,又支持函数式编程的语言,函数的使用方面有很多特点. 比如:闭包,装饰器,迭代器等 函数的高级应用 容器:生活中常见的容器有哪些?袋子,盆子,水杯,书包,铅笔盒... 容 ...
- python3 第二十六章 - 内置函数之Number相关
数学函数 函数 返回值 ( 描述 ) 实例 abs(x) 返回数字的绝对值,如abs(-10) 返回 10 print(abs(-10)) =======输出:====== 10 ceil(x) 返回 ...
随机推荐
- 深度视觉盛宴——CVPR 2016
小编按: 计算机视觉和模式识别领域顶级会议CVPR 2016于六月末在拉斯维加斯举行.微软亚洲研究院在此次大会上共有多达15篇论文入选,这背后也少不了微软亚洲研究院的实习生的贡献.大会结束之后,小编第 ...
- 2——PHP defined()函数
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- USB小白学习之路(11) Cy7c68013A驱动电路设计注意事项(转)
Cy7c68013A驱动电路设计注意事项 转自:http://group.chinaaet.com/116/79029#0-tsina-1-71467-397232819ff9a47a7b7e80a4 ...
- 基于Blazor写一个简单的五子棋游戏
写这个五子棋游戏,其实主要目的是想尝试一下微软新作Blazor.Blazor对于那些搞.NET的程序员,又想做一些前端工作,真的挺友好,不用一句JS就可搞定前端交互,美哉.现在已经有很流行的前端框架, ...
- 手把手教你轻松使用数据可视化BI软件创建某疾病监控数据大屏
灯果数据可视化BI软件是新一代人工智能数据可视化大屏软件,内置丰富的大屏模板,可视化编辑操作,无需任何经验就可以创建属于你自己的大屏.大家可以在他们的官网下载软件. 本文以某疾病监控数据大屏为例为 ...
- Spring-Boot-应用可视化监控
图文简介 快速开始 1.Spring Boot 应用暴露监控指标[版本 1.5.7.RELEASE] 首先,添加依赖如下依赖: <dependency> <groupId>or ...
- 解决ionic2/ionic3轮播图切换页面或者点击过后不自动轮图
我们在ionic2/ionic3开发的过程中会出现切换页面或者滑动切换轮播图出现轮播图不再轮播的情况,这其实需要一些配置. 首先在运用到轮播图的component中引入 import {ViewChi ...
- 浏览器内核之 HTML 解释器和 DOM 模型
微信公众号:爱写bugger的阿拉斯加如有问题或建议,请后台留言,我会尽力解决你的问题. 前言 此文章是我最近在看的[WebKit 技术内幕]一书的一些理解和做的笔记.而[WebKit 技术内幕]是基 ...
- 关于Spring和SpringMVC的总结
1.Spring中AOP的应用场景.AOP原理.好处? 答:AOP:Aspect Oriented Programming面向切面编程:用来封装横切关注点,具体可以在下面场景中使用: Authenti ...
- Nginx 推流 拉流 --- 点播直播
1. 准备环境 安装操作系统Cenos 配置yum源 yum:https://developer.aliyun.com/mirror/ Nginx依赖 gcc-c++ zlib pcre openss ...