函数 (二) 名称空间与作用域
一、什么是名称空间
我们写一段代码,里面肯定会定义一些变量名,函数名,而一旦我们运行代码,python解释器在加载这些代码的时候,会在内存中开辟一片空间专门用来存放这些名字以及这些名字所绑定的值的关系,
这块内存就被称为名称空间。
二、名称空间分类
名称空间分为三种:
△内置名称空间
内置名称空间是用来存放python解释器的一些内置方法明以及变量名的。这些名称是在解释器启动的时候就加载好的,我们随时可以调用。比如常见的 print( )、input( )、len( )等都是内置方法,我们在写代码的时候直接调用就行。而存放他们的名字的地方就叫做内置名称空间。
△全局名称空间
我们在写一段代码的时候,除了函数内所定义的变量以及函数外,其他的变量名以及函数名所存放的地方就叫做全局名称空间。一旦我们定义好这个变量或者函数,那么我们可以在代码的任意地方调用。
△局部名称空间
存放函数内定义的变量名以及函数内嵌套的函数名的地方叫做局部名称空间。他们只能在函数内部(包括函数内嵌套的函数内部)被调用。
三、名称的加载顺序
当我们打开解释器的时候内置变量以及函数就立即被加载,当我们执行一段代码的时候,全局变量以及函数才被加载,但是函数内部并不会被执行,只有在函数被调用的时候才会加载它内部的变量以及内嵌函数,所以,名称的加载顺序是:内置名称---->全局名称---->局部名称
四、名字的查找顺序
与名称的加载顺序刚好相反,python解释器在用到一个变量或者函数的时候,它会优先从局部名称空间去查找,如果没有,再到全部名称空间去查找,如果还没有,才会去内置名称空间去查找。
示例如下:
1 x = 0 2 def input(): 3 x = 1 4 print(x) 5 input()
#大家都知道python内置的一个方法叫做input( ),他是用来做用户交互的,但是如果我们自己定义一个input函数,
#那么再调用 input( )这个方法的时候,它会先从全局命名空间找input这个名字,如果找得到,那么它就不会再去
#内置名称空间去调用内置的input()方法了。而这个我们自定义的input方法内部有一个变量x,全局里还有一个变
#量也叫x,这个时候我们在函数内部调用x,那么解释器就会先从局部名称空间去找,很显然,它能找到,那么将不会再
#去全部或者内置名称空间里去找了,所以最后打印的x的值为1
五、作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效
六、global关键字和nonlocal关键字
△global
虽然在局部作用域内可以调用全局作用域的变量,但是它是没有权限修改,如果非要修改,那么就要用到global这个关键字了,如下:
1 a = 10 2 def func(): 3 global a 4 a = 20 5 6 print(a) #调用函数之前a的值为10 7 func() 8 print(a) #调用函数之后a的值就被修改为20了
△nonlocal
nonlocal关键字是用来改变外部离自己最近的局部变量
七、函数的嵌套
函数里面可以嵌套另外一个函数:
1 def outer(): 2 def inner(): 3 pass
八、闭包
满足一下两种情况的函数就成为闭包:
①有函数的嵌套
②内部函数调用外部函数的变量(不是指全局变量)
如下:
1 def outer(): 2 a = 1 3 def inner(): 4 print(a)
九、闭包的应用
下面的例子是写一个简单的爬网页函数,将指定网页的源代码打印出来:
1 from urllib.request import urlopen 2 3 def get_url(): 4 url = 'http://www.xiaohua100.cn/index.html' 5 def get_html(): 6 res = urlopen(url).read() 7 print(res) 8 get_html() 9 get_url()