zoukankan      html  css  js  c++  java
  • 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的作用就是在嵌套函数中使用,对上级函数的变量进行申明修改;

  • 相关阅读:
    Cannot initialize Cluster. Please check your configuration for mapreduce.framework.name
    docker-compose 安装solr+ikanalyzer
    centos 安装Python3
    spring+springmvc+mybatis 开发JAVA单体应用
    职责链模式例子
    ssm(spring、springmvc、mybatis)框架整合
    PAT (Advanced Level) Practise
    PAT (Advanced Level) Practise
    PAT (Advanced Level) Practise
    PAT (Advanced Level) Practise
  • 原文地址:https://www.cnblogs.com/zhongguiyao/p/14870859.html
Copyright © 2011-2022 走看看