默认参数的陷阱:
def qqxing(l = []): l.append(1) print(l) qqxing() #[1] qqxing([]) #[1] qqxing() #[1,1] qqxing() #[1,1,1] # 如果默认参数类型是可变数据类型, # # 那么每次调用函数的时候, # # 如果不传实参就共用这个数据类型的资源
函数的命名空间
1 函数进阶 2 a = 1 3 def func(): 4 print(a) 5 func() 6 7 def func(): 8 a = 1 9 func() 10 print(a) 11 12 命名空间和作用域: 13 14 命名空间 有三种 15 内置命名空间 ---- python解释器 16 就是python解释器一启动就可以使用的名字储存在内置命名空间中 17 内置的名字在启动解释器的时候被加载进内存 18 全局命名空间 ---- 我们写的代码但不是函数中的代码 19 是在程序从上到下被执行的过程中依次加载进内存的 20 放置了我们设置的所有变量名和函数名 21 局部命名空间 ---- 我们写的函数 22 就是函数内部定义的名字 23 当调用函数的时候 才会产生这个名称空间 随着函数执行的结束 这个命名空间就被回收 24 25 在局部: 可以使用全局,内置命名空间中的名字 26 在全局: 可以使用内置命名空间中的名字,不能使用局部 27 在内置: 不能使用局部和全局的名字 28 29 在正常情况下,直接使用内置的名字 30 当我们在全局定义了和内置名字空间中同名的名字,会使用全局的名字 31 当我自己有的时候 我就不找我的上级要 32 如果自己没有就找上级要 一次遍历所有上级直到内置空间 内置仍没有 就报错 33 多个函数应该拥有多个独立的局部名字空间 , 不互相共享 34 35 def input(): 36 print("in input now") 37 def func(): 38 input() 39 40 def func1(): 41 a = 1 42 def func2(): 43 a = 2 44 45 func() ==> 函数的内存地址() 46 函数名() 函数的调用 47 函数的内存地址() 函数的调用 48 49 作用域两种 50 全局作用域 --- 作用在全局 --- 内置和全局名字空间的名字 都属于全局作用域 ---- globals() 51 局部作用域 --- 作用在局部 --- 函数(局部名字空间中的名字属于局部作用域) ---- locals() 52 53 a = 1 54 def func(): 55 global a 56 a += 1 57 58 func() 59 print(a) 60 61 对于不可变的数据类型 在局部是可查看全局作用域中的变量 62 但是不能直接修改 63 如果想要修改,需要在程序的一开始添加global声明 64 如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作对全局的变量有效 65 a = 1 66 b = 2 67 def func(): 68 x = 'aaaa' 69 y = 'bbbb' 70 print(locals()) 71 #func() 72 print(globals()) 73 print(locals()) 74 75 globals() 永远打印全局的名字,尽量少的使用global,代码安全 76 locals() 打印当前局部的名字
函数的嵌套和作用域链
# def max(a,b): # return a if a>b else b # # def the_max(x,y,z): # 函数的嵌套调用 # c = max(x,y) # return max(c,z) # # print(the_max(1,2,3)) # 函数的嵌套定义 # 内部函数可以使用外部函数的变量 # a = 1 # def outer(): # a = 1 # def inner(): # b = 2 # print(a) # print('inner') # def inner2(): # nonlocal a #声明一个上层的局部变量,向上找的第一层 # a += 1 #不可变数据类型的修改 # print(a, b) # print('inner2') # inner2() # inner() # print('**a**', a) # outer() # print('全局的', a) # nonlocal 只能用于局部变量,找上层中离当前函数最近一层的局部变量 # 声明了nonlocal的内部函数的变量修改会影响到 离当前函数最近一层的局部变量,这就叫作用域链 # 注意找不到全局那里去,对全局无效 # 对局部是最近的那层 # # def func(): # print(123) #func() #函数名就是内存地址 # func2 = func #函数名可以赋值 # func2() # # l = [func,func2] #函数名可以作为容器类型的元素 # print(l) # # for i in l: # print(l) def func(): print(123) def wahaha(f): f() return f #函数名可以作为函数的返回值 qqxing = wahaha(func) #函数名可以作为函数的参数 qqxing() # 函数名是第一类对象 # 第一类对象(first-class object) # 1,可以在运行期创建 # 2,可用作函数参数或返回值 # 3,可存入变量的实体
闭包:
在定义的函数内再使用其他函数的行为,就称为闭包
# 闭包: 嵌套函数,内部函数调用外部函数的变量 # def outer(): # a = 1 # def inner(): # print(a) # print(inner.__closure__) # 打印结果出现cell就是闭包 # outer() # print(outer.__closure__) # def outer(): # a = 1 # def inner(): # print(a) # return inner # inn = outer() # inn() #import urllib # 模块 from urllib.request import urlopen # ret = urlopen('http://fulibus.net/').read() # print(ret) # def get_url(): # url = 'http://fulibus.net/' # ret = urlopen(url).read() # print(ret) # get_url() def get_url(): url = 'http://fulibus.net/' def get(): ret = urlopen(url).read() print(ret) return get get_func = get_url() get_func()