前面你看到嵌套两层的函数,也许你有感而发,想来点刺激的对不?那么如果每层内的变量名如果相同会怎样?拿个例子看下就知道:

报错了,报错信息大意是,本地变量‘num’引用前没有被赋值定义。这咋回事,我外层不是定义了吗?这个问题就涉及到今天要说的话题——函数作用域

函数作用域

1.作用域分三个:本地作用域(local),函数内作用域(enclosing),全局作用域(global)

2.三个作用域的优先级规则是这样:L>E>G>B

这里的B是什么呢?是Built-in,眼熟不,好像在哪里用过对吧?我们查看内置函数的命令是什么?dir(__builtins__)对吧?对了,就是这个,这个是内置作用域,知道就行,一般不会拿出来与前面三个作用域做比较

3.包含关系:

4.函数定义了本地作用域,模块定义了全局作用域:

1):每个模块都是一个全局作用域,所以全局作用域的范围是单个程序文件

2):每次对函数的调用都会创建一个新的本地作用域,赋值的变量除非声明为全局变量,否则均为本地变量

3):所有的变量名都可以归纳为本地,全局或内置(由__builtin__模块提供)

4):任何的函数在调用结束后,其内的变量都是消失

5.因为有了三个作用域,则会产生全局变量,局部变量

1)全局变量:指除了函数内的外层变量

2)局部变量:指函数内部的变量

6.局部变量和全局变量互不影响,即使变量名相同也如此。

看完以上的概念,上面的例子为何出错应该很好理解了。

在函数内修改外部的全局变量是不可行的,因为python会自动屏蔽掉,但函数内部都可以访问全局变量。

怎么屏蔽的呢?在函数内部创建一个与全局变量相同的局部变量来屏蔽,当你调用时因为优先级关系会自动的调用函数内部的那个变量,而外层的同名变量则永远也不会被调用

例:

结果显而易见,num并没有被改掉,这就是屏蔽的效果。num=100这个变量为全局变量,而函数temp内的num=50是局部变量。

那么我确实想改呢?方法是有的,加入一个global参数即可,例:

注意:global关键词不能写成  【global num=50 】,必须分开写,不然报错

改了对吧?但其实你有没有发现,其实是局部变量把全局变量改了,调用函数后,全局变量就变了

那假如我不给global是什么结果:

由此可以看出,在python中,函数内调用函数外的变量是可以的,当内部没有此变量时,会自动由优先级高到低一一审查,如果这个变量事先确实没有定义,才抛出一个错误【此变量没有被定义】。同时,我还要补充一点的是,代码运行方式是由上而下的,由上面两个例子可以看出。

那么你也许会想,因为上面的例子是局部变量改全局变量,我能不能全局变量改函数内的局部变量呢?这个问题留着,自己下去测试体会

那么既然有global,有没有和global类似的另一个关键词呢?有的——nonlocal,这里暂且不说,下面在合适的地方提到

7.内嵌函数:内嵌函数前面其实也提到了一点,就是函数内再嵌套一层或者多层函数,这种就叫内嵌函数

例:

注意:

1).在最后必须加入inn()这段代码,这才是调用inn函数的命令

2).调用函数只能调用外层函数,不能直接调用内层函数,不然报错,因为内部函数整作用域都在外部函数之内

3).inn()的调用并且是在out函数层内加入,而非在inn函数层加,如果不加入,则:

再看一个例子:

这里例子也很经典,符号‘.’是类的方法的调用【类在后面会讲到】,而此时是函数,函数的调用时是使用符号‘()’,所以以上代码就好解释了

注意,由于前面说的【任何函数调用结束时,其内的变量消失】,但此时的a1是对f1的调用,f1调用完变量就消失,而此时的a1调用时变量还在,因为在函数嵌套时,还有一层函数,所以并没有消失。

所以,总结:如果调用函数是直接返回内层函数(比如这里的a1函数调用),内层会自动记忆外层函数变量,这种行为就是函数的闭包(也叫闭合),也就是所谓的工厂函数

下一篇博文详细介绍闭包问题

洗礼灵魂,修炼python(22)--自定义函数(3)—函数作用域,闭包的更多相关文章

  1. Python开发——函数【装饰器、高阶函数、函数嵌套、闭包】

    装饰器 装饰器本质就是函数,为其他函数添加附加功能. 原则: 不修改被修饰函数的源代码 不修改被修饰函数的调用方法 装饰器知识储备:装饰器 = 高阶函数 + 函数嵌套 + 闭包 案例:求函数运行时间! ...

  2. 洗礼灵魂,修炼python(20)--自定义函数(1)—基础概念

    作为开发,那么我们前面学的那些知识其实够了,但是不够精简,也不好维护,比如需要打印斐波那契数列: 而当我们需要再次打印斐波那契数列,又要把这段代码加上,是不是很烦,有没有方法可以解决,当然可以,那就是 ...

  3. 洗礼灵魂,修炼python(24)--自定义函数(5)—匿名函数lambda

    在这个互联网时代,大家都喜欢匿名,匿名上网,匿名登录,匿名操作等等,都不喜欢实名对吧?(虽然说现在实名制已经快到来,题外话,扯远了),当然python里也有个不喜欢实名的,它的功效优点特殊,说强大吧? ...

  4. 洗礼灵魂,修炼python(5)--python操作符,内置函数

    前面提到了BIF(内置函数)这个概念,什么是内置函数,就是python已经定义好的函数,不需要人为再自己定义,直接拿来就可以用的函数,那么都有哪些BIF呢? 可以在交互式界面(IDLE)输入这段代码, ...

  5. 洗礼灵魂,修炼python(85)-- 知识拾遗篇 —— 深度剖析让人幽怨的编码

    编码 这篇博文的主题是,编码问题,老生常谈的问题了对吧?从我这一套的文章来看,前面已经提到好多次编码问题了,的确这个确实很重要,这可是难道了很多能人异士的,当你以为你学懂了,在研究爬虫时你发现你错了, ...

  6. 洗礼灵魂,修炼python(69)--爬虫篇—番外篇之feedparser模块

    feedparser模块 1.简介 feedparser是一个Python的Feed解析库,可以处理RSS ,CDF,Atom .使用它我们可从任何 RSS 或 Atom 订阅源得到标题.链接和文章的 ...

  7. 洗礼灵魂,修炼python(40)--面向对象编程(10)—定制魔法方法+time模块

    定制魔法方法 1.什么是定制魔法方法 首先定制是什么意思呢?其实就是自定义了,根据我们想要的要求来自定义.而在python中,其实那些所谓的内置函数,内置方法,内置属性之类的其实也是自定义出来的,不过 ...

  8. 洗礼灵魂,修炼python(6)--活起来的代码+列表

    活起来的用法: 使用input内置函数 注意python2中和python3中,input函数是不太一样的,python2中,input用户传入什么类型就是什么类型而python3中,不管传入什么类型 ...

  9. 洗礼灵魂,修炼python(29)--装饰器(1)—>利用经典案例解析装饰器概念

    前提必备 不急着进入正题,在前面函数作用域那一章介绍了闭包,全局变量局部变量,这里再看几个简单的闭包案例: 1):不带参数 注意: 1.这里的name属性是每个函数都有的,可以反馈函数名 2.temp ...

随机推荐

  1. Django--Session 操作

    Session Session的由来 Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要 ...

  2. Android 性能优化-启动时间

    adb shell am start -W -n com.xxxx(包名)/xxx.xxxActivity(launch Activity)

  3. Android生成二维码--拍照或从相册选取图片

    拍照或从相册选择图片是我们日常开发中经常使用到的,可以说是必须掌握的东西.上一篇我介绍了如何生成自定义二维码<Android生成自定义二维码>,其中logo和代替黑色色块的图片都是写死的, ...

  4. Eureka自我保护模式——难点重点

    一.开启Eureka自我保护模式访问Eureka主页时,如果看到这样一段大红色的句子: EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ...

  5. [深度学习]理解RNN, GRU, LSTM 网络

    Recurrent Neural Networks(RNN) 人类并不是每时每刻都从一片空白的大脑开始他们的思考.在你阅读这篇文章时候,你都是基于自己已经拥有的对先前所见词的理解来推断当前词的真实含义 ...

  6. 利用channel在goroutins之间控制同步和传递数据

    在java等代码中,我们查询数据库的操作: sql = "select * from ...."; result = db.query(sql) for(item in resul ...

  7. js从一个对象数组中根据属性值大小排序

    <script type="text/javascript"> var sdts = [ {name:"小明",age:30}, {name:&qu ...

  8. spring-boot-2.0.3源码篇 - 国际化

    前言 针对spring boot,网上已有很多优质的系列教程,我就不再班门弄斧了(实际上是担心没别人写的好,哈哈哈!).但是还是想蹭蹭spring boot的热度,即使不考虑微服务,spring bo ...

  9. 几种好用的经典webshell(php)

    php经典一句话: <?php echo shell_exec($_GET['cmd']);?> 中国菜刀:官网:www.maicaidao.co原理:上传一句话(<?php @ev ...

  10. Linux进程间通信(System V) --- 共享内存

    共享内存 IPC 原理 共享内存进程间通信机制主要用于实现进程间大量的数据传输,下图所示为进程间使用共享内存实现大量数据传输的示意图: 共享内存是在内存中单独开辟的一段内存空间,这段内存空间有自己特有 ...