Python全栈学习笔记day 10: 默认参数的陷阱、函数的命名空间、函数的嵌套和作用域链、闭包

 一、默认参数的陷阱

如果默认参数的值是一个可变数据类型,那么每一次调用函数的时候,如果不传值就公用这个数据类型的资源
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、局部命名空间 —— 函数
    # 就是函数内部定义的名字
    # 当调用函数的时候 才会产生这个名称空间 随着函数执行的结束 这个命名空间就又消失了

#在局部:可以使用全局、内置命名空间中的名字
#在全局:可以使用内置命名空间中的名字,但是不能用局部中使用
#在内置:不能使用局部和全局的名字的

  1. 在正常情况下,直接使用内置的名字
    #当我们在全局定义了和内置名字空间中同名的名字时,会使用全局的名字
    #当我自己有的时候 我就不找我的上级要了
    #如果自己没有 就找上一级要 上一级没有再找上一级 如果内置的名字空间都没有 就报错
    # 多个函数应该拥有多个独立的局部名字空间,不互相共享(如上图所示)
    
  2. 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()
  1. 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.内部修改这个变量如果想在外部有这个变量的第一层函数中生效

五、函数名的本质

  1. 可以被引用
    def func():
        print('in func')
    
    f = func
    print(f)

     

  2. 可以被当作容器类型的元素
    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']()

     

  3. 可以当作函数的参数和返回值(普通变量)

    第一类对象(first-class object)指
    1.可在运行期创建
    2.可用作函数参数或返回值
    3.可存入变量的实体。

六、闭包

闭包函数:

内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数
#函数内部定义的函数称为内部函数

def func():
    name = 'eva'
    def inner():
        print(name)

由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们就是想拿怎么办呢?返回呀!

我们都知道函数内的变量我们要想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?

是不是直接就把这个函数的名字返回就好了?

这才是闭包函数最常用的用法

  1. 判断闭包函数的方法__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()

     

  2. 闭包嵌套
    def wrapper():
        money = 1000
        def func():
            name = 'eva'
            def inner():
                print(name,money)
            return inner
        return func
    
    f = wrapper()
    i = f()
    i()

     

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值