一、作用域:
一个标识符的可见范围,这就是标识符的作用域,一般说的是变量的作用域
1.1、全局作用域
运行结果
在整个程序运行环境中可见。可以被多个函数重复多次使用
1.2、局部作用域
运行结果
这里调用a,显示未定义,原因在于函数是一个封装,他会开辟一个作用域,a被限制在这个作用域中了,所以a在函数外部不可见。
那如果一个函数内部出现一个跟全局变量一个相同的标识符名字呢?
如:
三、嵌套函数
在一个函数中定义宁外一个函数
先看一段代码:
运行结果:
调用inner函数呢?
运行结果:
也就是说,内部函数inner不能再外部直接使用,会显示未定义的标识符,因为它在函数外部不可见。其实inner就是标识符而已,就是一个函数outer内部定义的变量而已。
3.1、函数嵌套的作用域
请看一段代码并思考运行的结果是什么?
运行结果:
从执行结果可以得知,外部变量在内部作用域可见
在看一段代码:
思考运行的结果:
从上面结果中可以得出结论,如果定义了o=97,相当于在inner函数作用域中重新定义了一个新的变量o,但是这个变量o并不能覆盖外部作用域outer2中的变量o,对于innner来说,相当于自己作用域中定义的变量o
四、一个赋值语句的问题
先来看几段代码:
代码1
运行结果
代码2:
运行结果
这个很简单,下面呢对这段代码进行修改:
代码3
运行结果
前面没有问题,只是加了x+=1,就出错了?在来改下代码:
代码4
运行结果
这样就好了?为什么
再来看一个例子:
代码5
运行结果
代码5和代码3出现的错误一模一样,x=500,赋值及定义,在当前作用域中,如果你出现了谁等与谁,你在本地作用域当中定义了x,x就是当前作用域变量。也就是说,只要在函数中出现类似于x=变量的赋值语句,且此变量不加任何语句的修饰,那么此变量一定是当前函数中的局部变量,在此函数中所有x都是使用该x,所以y=x+1中的x也是局部变量,本地变量x还未赋值,不就引用了当然会报错。如何解决这个常见问题呢?使用global
四、global
声明标识符为全局变量
使用原则
外部作用域变量会在内部作用域可见,
例一:
例二:
结果是什么?
错误的,x先引用后赋值而python动态语言赋值才算定义,才能被引用。
如何改正呢?
下面来讲python函数中一个比较重要的东西:闭包
五、闭包
自由变量:未在本地作用域中定义的变量。例如定义在内层函数外的外层函数作用域中的变量
闭包:就是一个概念,出现在嵌套函数中,指的是内层函数引用到了外层函数的自由变量,就形成了闭包。
下面举一个例子,思考一下这里面有没有变量,有没有闭包?
在内层函数inc中,用到了外层函数局部变量c,不出错,具体分析如下:
运行结果:
再来看一个列子
运行结果:
这里面有闭包吗?如果在一个函数中使用了c= c就是inc的局部变量,跟外面counter函数中的c有关系吗?所以报错。如何解决?使用nonlobal如:
运行结果:
这是形成闭包的简单方式。
再来看一个列子
运行结果:
六、默认值作用域
下面先看一段代码:
例1:
运行结果:
x=出现了,x就是foo函数的局部变量,形参出现了,x都是局部变量,两次调用foo函数,x都一样。
再来看一段代码:
例2:
为什么第二次调用foo1()打印的是[1,1]?
y是局部变量,不可以在函数外访问,这个默认值不可能保存在局部变量作用域内
因为函数也是对象,每个函数定义被执行后,就生成了一个函数对象,和函数名。
函数是对象,有属性,pyhton把函数对象的默认值放在了函数对象的属性中,这个属于函数对象的整个生命周期。
查看foo1.__defaults__属性,他是个元组
如果没有缺省值?
例3:
函数调用放缺省值
运行结果:
好,了解了这个以后再来看一段代码:
例4:
运行结果:
函数地址没有变,就是说foo2函数这个对象没有变,调用它,它的属性__defaults__存默认值
z是引用类型,引用类型元素变动,并不是元组的变化
x,y是非引用类型,它们保存在缺省值属性元组中,将不能再改变了
下面再来看一段代码:
例5:keyword—only参数的缺省值
运行结果:
下面再来看一段代码:
例6:
运行结果:
x+=[1]是就地修改
改一下:
例7:
为什么三次都是[1]?
x=x+[1]是生成一个新对象覆盖x
可能你看不懂例6跟例7那我们看一个简单的你就懂了:
这里画图解释:
这是可变类型,x+=1 就地修改 x=x+1生成一个新对象覆盖x
不可变类型:
七、函数销毁:
del +函数标识符,引用计数减1
同名标识符覆盖原有定义,本质上也是使引用计数减1
python程序结束时,所有对象销毁
八、匿名函数lambda(没有名字的函数)
返回常量的函数
加匿名函数带有缺省值
keyword-only参数
可变参数
应用
defaultdict
sorted