• Python学习week5-函数返回值与作用域


    1、函数的返回值

    • python函数使用return语句返回"返回值";
    • 所有函数都有返回值,如果没有return,则会隐式调用return None;
    • return语句并不一定是函数语句块的最后一条语句
    • 一个函数可以存在多个return语句,但只有一条是可以被执行的,如果没有一条return语句被执行,则隐式调用return None;
    • 如果有必要,可以显示调用return None,也可以简写为return
    • 如果函数执行了return语句,函数就会返回,当前被执行的return语句之后的其他语句都不会执行了;
    • 返回值的作用:
      • 结束函数的调用
      • 返回值
        • 可以返回多个值?

    # 函数不能同时返回多个值,return 1,3,5 表示返回了一 个元组(1,3,5) # 返回值被python隐式封装成了一个元组;

    def showlist():
        return 1,3,5
    
    res=showlist()=(1,3,5)
    
    x,y,z=showlist=(1,3,5) # 使用解构可以取值方便

    # 函数的返回值可以使任意数据类型,但是能且只能返回一个;

    2、函数的嵌套

    # 函数嵌套:在一个函数内部定义了另外一个函数;

    # 内部函数对于外部不可见,不能直接对其调用,否则会抛异常;

    def outer():
        def inner():
            print('from inner')
        print('from outer')
        inner()
    
    outer()
    '''
    ==>
    from outer
    from inner
    '''
    inner() # NameError: name 'inner' is not defined

    3、作用域

    3.1、 变量的作用域

      作用域其实指的是变量的作用范围;变量并不是在哪个位置都可以访问的,访问权限取决于这个变量是在哪赋值的;也就是在哪个作用域内;

      通常来说,在编程语言中,变量的作用域从代码的结构形式来看的,有块级,函数,类,模块,包等由小到大;

      python中没有块级作用域,也就是类似if-else-if,for语句,with上下文管理,他们不存在作用域关系;

    3.2、python的作用域分层

    • L(Local)  局部作用域
    • E(Enclosing)嵌套作用域
    • G(Global)    全局作用域
    • B(Build-in)   内建作用域

      查找原则:L==>E==>G==>E

    3.3、作用域关系实例解析

    (1)下面代码运行结果:
      x=5   def foo()     x+=1     print(x)   foo()
    #代码分析:
    def foo():
        x+=1   
        '''
        x+=1 ==> x=x+1 python赋值即定义,x=x+1 相当于从新定义一个变量x,
        然后拿到一个未赋值的变量x,(这里的x指的是等式右边的x)给(等式左边的x)x赋值,
        相当于: 
          x
          x=x+1
        '''
        print(x) # UnboundLocalError: local variable 'x' referenced before assignment
    
    '''
    函数在定义阶段并没有报错,因为在定义阶段只检查语法;
    ''' 
    foo()
    (2)下面代码运行结果?
      name ='jack'   def f1():   print(name)   def f2():   name = 'eric'   f1()   f2()
    # 代码分析:
    常规错误理解:在f2内部定义一个变量name,然后调用f1(),执行打印print(name),这个name按照LEGB的查找关系应该找f2()内部的name,所以打印'eric';
    关键点函数的作用域关系在函数的定义阶段就已经形成,跟调用函数的位置无关;上面代码执行f1(),f1内部没有name变量,则向全局查找name,所有打印'jack'
    总结:
    作用域关系,在函数定义时候就已经固定,与调用位置无关,在调用函数时候,必须一定要回到函数原来定义的位置去找作用域关系;

    4、闭包函数

    # 自由变量:未在本地作用域中定义的变量,例如:定义在内层函数外的外层函数的作用域中的变量;

    # 闭包:就是一个概念,出现在嵌套函数中,指的是内层函数引用了外层函数的自由变量,就形成了闭包;

    # 闭包作用?

      一般情况下,如果一个函数调用结束,函数内部的所有东西都会释放,还给内存,函数的局部变量消失;

      但是闭包是一种特殊情况,如果外部函数在调用结束后发现自己的临时变量会被内部函数引用,就会把这个临时变量绑定给内部函数,然后再结束;

    # 理解闭包函数
    # 1、简单闭包函数
    def counter():
        c = [0]
        def inc():
            c[0] += 1  #应用的是自由变量正式counter的变量c
            return c[0]
        print(c[0])
        return inc
    
    #counter()()
    foo = counter()    # counter()调用结束将,变量c=[0]并不销毁;
    print(foo(),foo())   #调用的是inner()
    print(foo())
    
    # 2、分析函数打印结果
    def count():
        fs=[]
        for i in range(1,4):  # for循环3次相当于在count函数内定义了3次函数f 
            def f():
                return i*i
            fs.append(f)
        return fs
    
    f1,f2,f3=count() # count函数调用结束,for循环在调用结束后 变量i=3 最后内存中i记录的值为3;
    
    print(f1()) # 调用f1()相当于调用f(),return i*i 所有返回9
    print(f2())
    print(f3())

    # 3、将上面函数稍作修改
    def count1():
    fs=[]
    for i in range(1,4):
    def f():
    return i*i
    fs.append(f())
    return fs
    print(count1())
    f1,f2,f3=count()
    print(f1,f2,f3)
    # 上面代码在for循环定义f函数后直接对f函数进行调用,然后将返回值i*i 添加到列表fs,由于i的取值是发生在for循环一次之后所以对应的i取值为1,2,3

    5、nonlocal关键字

    #  使用了nonlocal关键字的变量 ,将变量标记为不在本地作用域定义,而在上级的某一级局部作用域中定义,但不能是在全局作用域中定义;

    def bar():
        x=0
        def foo():
            nonlocal x  # 将x标记为非本地变量
            x+=1    # x=x+1  此时x向外层函数找,x=0,x=x+1 ,形成闭包;
            return x
        return foo
    
    res=bar()()
    print(res)

    6、默认值的作用域

    • 函数也是对象,python 把函数的默认值放在了属性中,这个属性就伴随着这个函数对象的整个生命周期; 
    # 参数为引用类型实例
    def
    foo(l:list=[]): l.append(1) return l print(foo(),id(foo)) print(foo.__defaults__) print('#'*30) print(foo(),id(foo)) print(foo.__defaults__) ''' [1] 1966940858160 ([1],) ############################## [1, 1] 1966940858160 ([1, 1],) foo地址并没有变,就是说foo这个对象没有变,调用它,它的属性__defaults__ 中使用元组保存默认值;
    l是列表,__defaults__ 中元组记录的是l引用地址,列表元素的增加,列表的地址不会发生改变;
    '''

    # 参数为非引用类型
      def foo(w,u='abc',z=123):
        u = 'xyz'
        z = 789
        print(w,u,z)
      print(foo.__defaults__)
      foo('test')
      print(foo.__defaults__)
      ''’
      运行结果:
      ('abc', 123)
      test xyz 789
      ('abc', 123)
      '''
      分析:属性__defaults__中使用元组保存所有位置参数默认值,它不会因为在函数体内使用了它而发生改变;
      
      # 带keyword-only参数
      def foo(w,u='abc',*,z=123,zz=[456]):
        u = 'xyz'
        z = 789
        zz.append(1)
        print(w,u,z,zz)
      print(foo.__defaults__)
      foo('tes')
      print(foo.__kwdefaults__)
      '''
      运行结果:
      ('abc',)
      tes xyz 789 [456, 1]
      {'z': 123, 'zz': [456, 1]}

      属性__kwdefaults__ 中使用字典保存所有keyword-only 参数的默认值;
      使用可变类型作为形参默认值的时候,就可能修改这个默认值;
      '''
    • 使用可变类型作为形参默认值的时候,就可能修改这个默认值;

    (1)函数体内,不改变默认值;

    def foo(xyz=[],u='abc',z=123):
        xyz = xyz[:]     #影子拷贝
        xyz.append(1)
        print(xyz)
    print(foo.__defaults__)
    foo()
    print(foo.__defaults__)
    foo([10])    
    foo()
    print(foo.__defaults__)
    foo([10,5])
    print(foo.__defaults__)
    '''
    运行结果:
    ([], 'abc', 123)
    [1]
    ([], 'abc', 123)
    [10, 1]
    [1]
    ([], 'abc', 123)
    [10, 5, 1]
    ([], 'abc', 123)
    '''
    # 函数中的xyz 都是传入参数或者默认参数的副本,如果就想修改原参数,不可以;

    (2)使用不可变类型的默认值;

    def foo(xyz=None,u='abc',z=123):
        if xyz is None:
            xyz = []
        xyz.append(1)
        print(xyz)
    print(foo.__defaults__)
    foo()
    foo()
    print(foo.__defaults__)
    foo([10])
    print(foo.__defaults__)
    foo([10,5])
    print(foo.__defaults__)
    
    '''
    (None, 'abc', 123)
    [1]
    [1] (None, 'abc', 123) [10, 1] (None, 'abc', 123) [10, 5, 1] (None, 'abc', 123)
    ''' # (1)如果使用缺省值None就创建一个列表 # (2)如果传入一个列表,就修改这个列表
  • 相关阅读:
    无题
    一周损兵又折将
    防火墙安装配置(准备)
    徐州项目顺利验收
    悲惨的圣诞节
    [原]防火墙安装配置(日志)
    [转]有关加薪申请资料
    解决FireFox下XML对象转化成字符串
    ASP.NET Application and Page Life Cycle(asp.net生命周期)
    C# 利用反射动态创建对象[转]
  • 原文地址:https://www.cnblogs.com/soulgou123/p/9570045.html
Copyright © 2020-2023  润新知