python学习日记(函数进阶)
命名空间
内置命名空间
存放了python解释器为我们提供的名字:print,input...等等,他们都是我们熟悉的,拿过来就可以用的方法。
内置的名字在启动解释器(程序运行前)的时候被加载在内存里。
全局命名空间
放置了我们设置的所有变量名和函数名。
是在程序从上到下被执行的过程中依次加载进内存里。
局部命名空间
函数内部定义的名字。
调用函数的时候。才会产生这个名称空间,函数执行结束的时候,这个名称空间就消失(被释放)了。
使用规则
在局部:可以使用全局、内置命名空间中的名字
在全局:可以使用内置命名空间中的名字,但不能使用局部中的名字
在内置:不能使用全局和局部的名字
名字局部找不到,往上一级找,再找不到再上一级,内置空间都没有的话,就会引发异常
自己当前级别有的话,就不去找上一级要了
一、
b = '全局' def func(): a = '局部' print(b)#内部可以使用全局 b 以及内置 print func() print(a)#全局不能使用内部
二、
当全局定义的名字和内置的名字相同时,会使用全局定义的名字。
def input(x): print('全局函数') input('请输入:')
# def input(x): # print('全局函数') input('请输入:')
附加一:函数名的本质:内存地址
def input(x): print('全局函数') def func(): # input = '局部变量' print(input) func() print(func) # 函数名 :指向内存地址(同变量),函数名() :函数的调用
附加二:多个函数拥有多个独立的局部名字空间,不互相共享
def hh(): a = 'hh' def kk(): print(a)#无法使用另一个函数定义的变量 kk()
作用域
概述
作用域就是做用范围,按照生效范围可以分为局部作用域和全局作用域。
全局作用域:包含内置名称空间,全局名称空间,在整个文件的任意位置都能被引用,全局有效
局部作用域:局部名称空间,只能在局部范围内生效
global
a = 1 def kk(): # global a a += 1 print(a) kk() #对于不可变数据类型,局部可以查看全局作用域中的变量,但不能直接修改 #若想修改,需要在程序一开始之前添加 global 声明
a = 1 def kk(): global a a += 1 print(a) kk() print(a)#全局的也被修改
补充:出于对代码的安全性考虑,我们应该尽量少的或者不使用global
a = 1 def kk(): a = 2 return a#利用返回值来代替global a = kk()#调用的时候,才会执行函数,不调用就不会影响全局变量 a print(a)
globals 和 locals
a = 1 b = 2 def hh(): x = 'happy' y = 'day' print(globals())#globals() 函数会以字典类型返回当前位置的全部全局变量。 print(locals()) #locals() 函数会以字典类型返回当前位置的全部局部变量。 hh() print(globals()) print(locals())
函数的嵌套
引子
比较三个数的大小
def max(a,b): return a if a > b else b def bmax(x,y,z): c = max(x,y)#函数的嵌套 return max(c,z) print(bmax(1,2,3))
函数内部调用其他函数,即为函数的嵌套。最常见的为定义一个函数,函数体里面含有print()函数。
例子
1、
def outer():#外部函数 def inner():#内部函数 print('inner') inner() outer()
2、
def outer():#外部函数 a = 1 def inner():#内部函数 print(a)#内部函数可以使用外部函数的变量 print('inner') inner() outer()
3、
def outer():#外部函数 a = 1 def inner():#内部函数 b = 2 print(a)#内部函数可以使用外部函数的变量 print('inner') def inner2(): print(a,b)#内部函数可以使用外部函数的变量 print('inner2') inner2() inner() outer()
4、global只能修改全局变量
a = 1#全局变量 def outer(): a = 1#局部变量 def inner(): b = 2 print(a) def inner2(): global a#只修改了全局,不能修改局部 a +=1 inner2() inner() print('局部:',a) #局部变量没有被修改 outer() print('全局:',a)#全局变量被修改
5、nonlocal,修改当前变量最近的一个函数里面的此变量,没有的话继续往上一层找,但不能修改全局变量
5.1
a = 1#全局变量 def outer(): a = 1#局部变量 def inner(): b = 2 print(a) def inner2(): nonlocal a#只能修改局部,不能修改全局 a +=1 inner2() inner() print('局部:',a) #局部变量被修改 outer() print('全局:',a)#全局变量没有被修改
5.2
a = 1#全局变量 def outer(): a = 1#不是最近的,不考虑 def inner(): a = 1#最近的变量 a,进行修改 b = 2 print(a) def inner2(): nonlocal a#只能修改局部,不能修改全局 a +=1 inner2() print('局部最近',a)#局部变量被修改 inner() print('局部较远:',a) #没有被修改 outer() print('全局:',a)#全局变量没有被修改
函数名的本质
一、函数名可以被赋值
def hh(): print('yes') # hh() kk = hh#函数名可以赋值 kk() li = [hh,kk]#函数名可以作为容器类型的元素 print(li)#函数名就是地址 for i in li: i()
二、函数名可以作为参数和返回值
作为返回值和参数
def hh(): print('hhhhh') def kk(k): k() #加上括号就是调用函数 return k#函数名可以作为返回值 # hh() q = kk(hh) #返回值,返回的是 k ,k 为 hh ,即内存地址 print(q) q()#同下,内存地址加括号,调用函数 kk(hh) #hh就是内存地址,函数名可以作为函数参数
可以当作函数的参数和返回值,即就当普通变量用
第一类对象(first-class object)指 1.可在运行期创建 2.可用作函数参数或返回值 3.可存入变量的实体
函数闭包
定义
嵌套函数,内部函数调用外部函数的变量。
调用全局变量不属于闭包。
可以使用 __closure__ 来判断是否是闭包
def hh(): a = 1 def kk(): print(a) print(kk.__closure__) hh() print(hh.__closure__)
闭包函数最常用的用法
保存函数的状态信息,使函数的局部变量信息依然可以保存下来。
def hh(): a = 1 def kk(): print(a) return kk #返回 kk :函数地址 x = hh()#调用之后接收返回值,即接收的为地址 kk x()#地址加括号,调用
使得函数hh虽然被调用,但是其局部信息依然被保存,x() 能成功输出为验证。
举个栗子
1、
from urllib.request import urlopen sc = urlopen('https://www.baidu.com').read() print(sc)
2、闭包实现
def get(): url = 'https://www.baidu.com' def get_url(): sc = urlopen(url).read() print(sc) return get_url#返回函数名 arg = get() arg()#加括号调用,调用一次,执行一次,保存了局部变量信息
pass