15.函数的返回值与嵌套函数

(十七)函数的返回值与嵌套函数

1:什么是返回值

    返回值指的是函数返回的结果
    # 示例1
    def add(x, y): 
        print(x, y)
        return x + y   # 返回值, return以后的语句将不会再执行
        print(x)
        print(y)
    add(1,2)
    # 示例2
    def add(x, y):
        print(x, y)
        return x + y   # 函数体内,碰到return语句,函数执行完毕,之后的语句将不会再执行
        return x - y   # 不会再次执行
    add(1,2)

2:函数的隐式返回和显示返回

    Python函数都有返回值,如果函数体内没有return语句,那么默认返回None,称为隐式返回
    如果有return语句,直接返回,称为显示返回

3:函数多值返回

    函数可以返回多个值
    def get_data(x,y,z):
        return x + 1, y + 1, z + 1
    print(get_data(1,2,3))  # 得到的是一个元组
    def get_data(x,y,z):
        return [x + 1, y + 1, z + 1]
    print(get_data(1,2,3))  # 得到的是一个列表

4:什么是嵌套函数

    def outer_function():
        # 内部函数
        def inner_function():
            print("inner_function")
        print("outer_function")
        # 内部调用
        inner_function()
    outer_function()
    注意:inner_function函数只能在outer_function函数内部调用,无法再outer_function函数外部被调用

5:函数作用域

    什么是作用域:作用域指的是,一个标识符的作用范围就是这个标识符的作用域
    # 示例1: z变量只能在函数内部被访问无法在函数外部被访问,z变量的作用域就是add函数内部
    def add(x, y):
        z = 100
        print(x, y , z)
    add(1,2)
    print(z)
    # 示例2:z可以在add函数外部被访问到,
    z = 100
    def add(x, y):
        print(x, y , z)
    add(1,2)
    print(z)
    小结:
    全局作用域:整个运行环境中都可见,也就是整个模块内可见
    局部作用域:函数或类中可见,函数体或类就是作用域

6:函数的闭包

    # 对比下列中的函数
    # 示例1
    x=5
    def add():
        y = x + 1
    add()
    # 示例2
    x=5
    def add():
        x = x + 1  # 报错:local variable 'x' referenced before assignment
    add()
    报错原因分析:
        在示例1中,函数内部引用的x为函数外部的x, 因此x的值为5
        在示例2中,函数内部重新定义了x的值,那么整个函数内部都会使用这个内部x,因此在运算x + 1的时候,x还没有完成定义就被引用了,这里的x引用的一定是内部正在定义的x,不是函数外部的x=5
    # 示例3:
    x=5
    def add():
        print(x) # 这里的x引用的是x = 1的x,但是执行print(x)时,x还没有被定义,所以报错:local variable 'x' referenced before assignment
        x =  1
    add()
    # 4 闭包: 内部函数引用了外部函数的变量,这就是闭包的定义
    def outer_function():
        x = 100
        def inner_function():
            print(x)        # 内部函数引用了外部函数的自由变量
        return inner_function
    ret = outer_function()
    ret()

7:nonlocal关键字、global关键字

    # 1:global关键字
    x=5
    def add():
        global x  # 使用global关键字,指定x的引用全局的x变量
        x = x + 1
    add()
    # global关键字对全局变量的污染,因此需要慎用
    x = 100
    def foo():
        global x  # x被声明了全局变量
        x = 10
        x += 1
        print(x)  # x的值为11
    foo()
    print(x)      # x的值为11, 因此global关键字污染了全局变量x
    # 2:nonlocal关键字
    def outer_function():
        x = 100
        def inner_function():
            x = x + 1       # 这样会报错
            print(x)
        return inner_function
    ret = outer_function()
    ret()
    # 修改上面的代码,使用nonlocal关键字
    def outer_function():
        x = 100
        def inner_function():
            nonlocal x
            x = x + 1       # 这样会报错
            print(x)
        return inner_function
    ret = outer_function()
    ret()
    注意:nonlocal关键字的意义在于:内部函数的变量引用的外部函数变量的值,不是全局作用域的值,因此不会污染全局作用域

8:函数默认值的作用域

    # 示例, 函数的默认值绑定在函数对象的整个生命周期,不会因为函数内部对默认值操作而发生改变
    def add(lst = []):
        lst.append('hello')
        print(lst)
    add() # 输出:['hello']
    print('id={}'.format(id(add)))   # 函数对象的id值不变,调用的是同一个函数
    add() # 输出['hello', 'hello']
    print('id={}'.format(id(add)))   # 函数对象的id值不变,调用的是同一个函数
    # 查看函数的位置参数的默认值
    print(add.__defaults__)
    # 查看函数的关键字参数的默认值
    print(add.__kwdefaults__)
    # 可以使用两种方法解决函数默认值带来的弊端:
    # 1:浅拷贝
    def add(lst = []):
        lst = lst[:]
        lst.append('hello')
        print(lst)
    add() # 输出:['hello']
    add() # 输出:['hello']
    # 2:参数值判断
    def add(lst=None):
        if lst is None:
            lst = []
        lst.append(1)
        print(lst)
    add()
    print(add.__defaults__)
    add()
    print(add.__defaults__)
    add([1,2,3])
    print(add.__defaults__)
    add([4,5,6])
    print(add.__defaults__)

9:函数销毁

    1:函数运行结束时销毁
    2:del 删除函数对象
    3:重命名覆盖函数对象
    def add():
        print('add')
    del add
    add()

1.什么是返回值

  • 返回值指的是函数返回的结果;

  • return执行完毕后面的语句将不会再执行;

  • 如果一个函数里面有两个return,前面return执行完毕,后面的return也不会执行;

2.函数的隐式返回和显示返回

  • Python函数都有返回值,如果有return语句,是显式返回;

  • 如果没有return语句,默认返回None,是隐式返回;

3.函数多值返回

  • 如果返回多个值通过逗号分开,会把值进行压缩,封装成一个元组;

  • 如果返回一个列表,得到的就是一个列表;

4.什么是嵌套函数

  • 嵌套函数的内部函数只能在包含它的函数的直接父级调用,也就是只能在包含它的外部函数中调用;

  • 嵌套函数层数不宜过深,一般3层以内即可,太深不够直观,容易造成代码混乱;

5.函数作用域

  • 作用域指的是,一个标识符的作用范围就是这个标识符的作用域;

  • 在函数里面定义的变量(即局部作用域)只能在函数体内部被访问,函数外部不能访问;

  • 在函数外部定义的变量(即全局作用域)能在函数体外部被访问,也能在函数体内部被访问;

6.函数的闭包

  • 闭包:内部函数引用了外部函数的变量,这就是闭包的定义;

  • 如果函数体想访问变量,只能在变量定义之后才能访问;

  • 如果要访问函数体内部的函数,可以先把内部函数的函数名作为外部函数的返回值,把外部函数的引用赋值给变量,再调用变量;

7.关键字

  • global关键字:可以指定变量为全局变量,但是global关键字会污染全局变量,也就是会覆盖之前全局变量的值,所以最好慎用;

  • nonlocal关键字:可以申明内部函数的变量引用的是外部函数变量的值(作用域在外部函数),不是全局作用域的值,因此不会污染全局作用域;

8.函数默认值的作用域

  • 同一个函数的生命周期相同,函数的默认值会绑定在函数的整个生命周期上,不会因为函数内部对默认值的操作而发生改变;

  • 可以使用浅拷贝copy(简写[:])来清空默认值,那每次调用函数,默认值都为初始值;

  • 也可以通过参数值判断来给默认值重新赋值,那每次调用函数,默认值都为初始值;

9.函数销毁

  • 可以通过 del 函数名 的方式来删除函数,再调用函数时,就会报错不存在;

课后补充:

问题:闭包的具体使用?

答:闭包的理解就是在函数a里面再嵌套一个函数b等,那么函数b里面都可以引用函数a的变量,然后函数a返回值是函数b,这样就形成了闭包,这样就相当于说,这个函数b就是一个封闭的函数,只能在a函数中使用。

闭包的具体使用最好的例子就是后面的装饰器(21节:https://www.9xkd.com/user/plan-view.html?id=1603899338

问题:嵌套函数的作用?

嵌套函数很方便,比如:一个函数里面有很多相同代码,但是其他地方不需要用,这个时候不需要定义公用函数,可以直接在这个地方定义一个内部函数,方便仅在当前这个函数里面公用;

子函数里面可以直接引用上层函数的变量,也可以直接引用全局变量;

嵌套还有一个好处就是,在各个函数里面定义的变量,另外的函数互相不会影响(嵌套一般也不要嵌套很多层,最好不超过3层);

问题:关于global关键字具体怎么使用呢?

答:global关键字的作用就是把局部变量修改为全局变量,它会覆盖原有的全局变量,所以我们要慎用global,能不用就不用,避免造成全局污染; 如下举个例子讲解一下,如下图所示:

fun2中变量c现在是局部变量,我们如果通过global声明c之后,就全局都可以调用c了,也就相当于c变成了全局变量;

fun3中,如果一个函数已经声明了一个局部变量c,并且赋值了999。然后在这个函数里面,再使用global 声明一个全局变量c,那么后面的子级函数和外部引用c都是引用的全局变量c的值;

但是如果我们在同级函数中引用c的话,引用的依旧是局部变量c的值。

是不是感觉有点乱,所以,我们为了避免混乱,建议不要声明了局部变量后,又吧它改为全局变量的形式。也就是说在同一级中,不要声明了局部变量c后,然后又声明全局变量c,如下,这样是错的:

问题:nonlocal关键字的具体使用?

答:如下图所示:nonlocal关键字用来标识变量所在的命名空间,用在嵌套函数中,表示外层;

在外层的变量a为全局变量,不属于嵌套函数,所以,用不能在函数外面使用nonlocal a,这样会报错(总之nonlocal不能引用全局变量);

在fun1中b属于嵌套函数中的外层函数的变量,所以,在fun2中使用nonlocal修改b是没有问题的;

nonlocal是可以隔层的,不一定需要是直接的父层,例如:我在fun1中定义的b,在fun3中的nonlocal也可以声明修改b,当然fun2中也可以修改,并且如果是在fun3中修改b,那使用时就会以fun2中的b的执行结果为初始值(也就是初始值不在是fun1中b的值了);

nonlocal的作用就是在嵌套函数中使用,对上级函数的变量进行申明修改;

原文地址:https://www.cnblogs.com/zhongguiyao/p/14870859.html