一、默认参数的陷阱
如果默认参数的值是一个可变数据类型,那么每一次调用函数的时候,如果不传值就公用这个数据类型的资源
def qqxing(k,l = {}):
l[k] = 'v'
print(l)
qqxing(1) #{1: 'v'}
qqxing(2) #{1: 'v', 2: 'v'}
qqxing(3) #{1: 'v', 2: 'v', 3: 'v'}
def qqxing(l = []):
l.append(1)
print(l)
qqxing() #[1]
qqxing() #[1,1]
qqxing() #[1,1,1]
二、命名空间
1、内置命名空间 —— python解释器 # 就是python解释器一启动就可以使用的名字存储在内置命名空间中 # 内置的名字在启动解释器的时候被加载进内存里 2、全局命名空间 —— 我们写的代码但不是函数中的代码 # 是在程序从上到下被执行的过程中依次加载进内存的 # 放置了我们设置的所有变量名和函数名 3、局部命名空间 —— 函数 # 就是函数内部定义的名字 # 当调用函数的时候 才会产生这个名称空间 随着函数执行的结束 这个命名空间就又消失了 #在局部:可以使用全局、内置命名空间中的名字 #在全局:可以使用内置命名空间中的名字,但是不能用局部中使用 #在内置:不能使用局部和全局的名字的
-
在正常情况下,直接使用内置的名字 #当我们在全局定义了和内置名字空间中同名的名字时,会使用全局的名字 #当我自己有的时候 我就不找我的上级要了 #如果自己没有 就找上一级要 上一级没有再找上一级 如果内置的名字空间都没有 就报错 # 多个函数应该拥有多个独立的局部名字空间,不互相共享(如上图所示)
-
func --> 函数的内存地址 函数名() 函数的调用 函数的内存地址() 函数的调用
三、作用域两种
全局作用域 —— 作用在全局 —— 内置和全局名字空间中的名字都属于全局作用域 ——globals()
局部作用域 —— 作用在局部 —— 函数(局部名字空间中的名字属于局部作用域) ——locals()
对于不可变数据类型 在局部可是查看全局作用域中的变量 # 但是不能直接修改 # 如果想要修改,需要在程序的一开始添加global声明 # 如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效
a = 1
def func():
global a
a = 2
func()
print(a)
globals 永远打印全局的名字
locals 输出什么 根据locals所在的位置
a = 1
b = 2
def func():
x = 'aaa'
y = 'bbb'
print(locals())
print(globals())
func()
print(globals())
print(locals()) #本地的
四、函数的嵌套
函数的嵌套定义:内部函数可以使用外部函数的变量,如:
def f1():
def f2():
def f3():
print("in f3")
print("in f2")
f3()
print("in f1")
f2()
f1()
-
nonlocal 只能用于局部变量 找上层中离当前函数最近一层的局部变量 声明了nonlocal的内部函数的变量修改会影响到,离当前函数最近一层的局部变量,对全局无效,对局部也只是对最近的一层有影响
a = 0
def outer():
a = 1
def inner():
#a = 2
def inner2():
nonlocal a
print(a)
inner2()
inner()
outer() #输出:1
a = 0
def outer():
#a = 1
def inner():
a = 2
def inner2():
nonlocal a
print(a)
inner2()
inner()
outer() #输出:2
注:
1.外部必须有这个变量
2.在内部函数声明nonlocal变量之前不能再出现同名变量
3.内部修改这个变量如果想在外部有这个变量的第一层函数中生效
五、函数名的本质
- 可以被引用
def func(): print('in func') f = func print(f)
- 可以被当作容器类型的元素
def f1(): print('f1') def f2(): print('f2') def f3(): print('f3') l = [f1,f2,f3] d = {'f1':f1,'f2':f2,'f3':f3} #调用 l[0]() d['f2']()
-
可以当作函数的参数和返回值(普通变量)
第一类对象(first-class object)指 1.可在运行期创建 2.可用作函数参数或返回值 3.可存入变量的实体。
六、闭包
闭包函数:
内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数
#函数内部定义的函数称为内部函数
def func():
name = 'eva'
def inner():
print(name)
由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们就是想拿怎么办呢?返回呀!
我们都知道函数内的变量我们要想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?
是不是直接就把这个函数的名字返回就好了?
这才是闭包函数最常用的用法
- 判断闭包函数的方法__closure__
#输出的__closure__有cell元素 :是闭包函数 def func(): name = 'eva' def inner(): print(name) print(inner.__closure__) return inner f = func() f() #输出的__closure__为None :不是闭包函数 name = 'egon' def func2(): def inner(): print(name) print(inner.__closure__) return inner f2 = func2() f2()
- 闭包嵌套
def wrapper(): money = 1000 def func(): name = 'eva' def inner(): print(name,money) return inner return func f = wrapper() i = f() i()