zoukankan      html  css  js  c++  java
  • 可变长参数、函数对象、嵌套、名称空间和作用域

    来了,来了,它真的来了,超级台风利奇马已经来了,晚上正吃着可口的晚餐,吃完到外面风雨交加,整个人都凌乱了,不吐槽了,还是好好学习吧!

    可变长参数、函数对象、嵌套、名称空间和作用域

    一、可变长参数

    1.1 可变长形参之*

    用*接收溢出的位置实参,以元组的形式存储,然后复制给*后的参数,*后参数名固定为args

    def sum_self(*args):   # 用*接收位置实参1,2,3,4,存储为元组(1,2,3,4),赋值给args
        res=0
        for num in args:
            res+=num
        return res
    res = sum_self(1,2,3,4)
    print(res)     # 10
    

    1.2 可变长实参之*

    实参中的*会将*后的参数值循环取出,打散成位置实参

    def func(x,y,z,*args):
        print(x,y,z,args)
    
    func(1,*(1,2),3,4)   #  *循环取出(1,2),打散成位置实参,这样位置实参就变成1,1,2,3,4,
    #  形参x,y,z对应的实参就为1,1,2,形参中用*args接收溢出的位置实参3,4,存储为元组(3,4)
    

    1.3 可变长形参之**

    形参中的会将溢出的关键字实参全部接收,然后存储字典的形式,然后把字典赋值给后的参数。需要注意的是:**后的参数名约定俗成为kwargs

    def func(**kwargs):
        print(kwargs)
    func(a=5,b=6)      # 形参中的**接收溢出的两个关键字实参,存储为字典{'a':5,'b':6},并赋值给kwargs
    

    1.4 可变长实参之**

    实参中的**,**会将**后参数的值循环取出,打散成关键字实参。以后但凡碰到实参中带**的,它就是关键字实参,应该马上打散成关键字实参去看

    ef func(x,y,z,**kwargs):
        print(x,y,z,kwargs)     #  1 3 4 {'a': 1, 'b': 2}
    func(1,3,4,**{'a':1,'b':2})
    

    二、函数对象

    • 先定义一个函数:函数是第一类对象,即函数可以被当做数据处理
    # 把函数当做对象来用
    def func():
        print('from func')
    
    print(func)   # 这里函数func就可以当做数据来print,直接print(函数名),会输出函数的内存地址,<function func at 0x000001EBDC641E18>
    
    • 函数名等同于变量名,即变量名有的方法,函数名同样有,可以用来引用、当做参数传给一个函数、当做函数的返回值、作为容器类数据类型的元素
    • 以上面定义的函数func为例,有以下四个功能:

    2.1、引用

    a = 1
    print(a)  # 变量名
    
    b = a  # b =1
    # 变量名可以被引用,函数名也可以被引用
    
    f = func  # func可以加()调用,那么f也可以加()调用
    print(f)    # 打印func内存地址,<function func at 0x000001EBDC641E18>
    f()  # 相当于func() ,打印结果为from func
    

    2.2、当做实参参数传给一个形参参数

    def f2(name):  # name = func
        name()  # func()   
    
    f2(func)     # 这整个函数就能实现函数func()的调用,输出结果为from func
    

    2.3、可以作为容器类数据类型中的元素

    lt = [1, 2, a, func]
    lt[-1]()   # 直接实现func调用功能,最后输出结果from func
    

    2.4 可以当做函数的返回值

    def f3(name):  # name = func
        return name  # name = func
    
    res = f3(func)  # res = func
    print(res)    # 打印func的内存地址,<function func at 0x000001EBDC641E18>
    res()     # 调用函数func(),打印结果为from func
    

    三、函数的嵌套

    3.1 函数的嵌套定义

    • 函数内部定义的函数,无法在函数外部使用内部定义的函数
    def f1():
        def f2():
            print('from f2')
        f2()
    
    f2()  # NameError: name 'f2' is not defined,在函数外部就不能使用内部函数f2
    
    • 正确的嵌套定义

      def f1():
          def f2():
              print('from f2')
          f2()
      f1()
      
    • 通过函数传参求圆的面积或者周长

    from math import pi
    
    def circle(radius, action='area'):   # radius为半径
        def area():
            return pi * (radius**2)
    
        def perimeter():       # 定义周长函数
            return 2*pi*radius
        if action == 'area':
            return area()
        else:
            return perimeter()
    
    
    print(f"circle(10): {circle(10)}")
    print(f"circle(10,action='perimeter'): {circle(10,action='perimeter')}")
    

    3.2 函数的嵌套调用

    def self_max(x,y):
        if x>y:
            return x
        return y
    def self_4_max(x,y,z,a):
        res1=self_max(x,y)     # 在这个函数内调用上面的函数
        res2=self_max(z,a)
        res=self_max(res1,res2)
        return res
    res=self_4_max(10,40,20,80)
    print(res)             # 80
    

    四、名称空间和作用域

    4.1 名称空间

    名称空间用来存放变量名和函数名

    4.1.1 内置名称空间

    • 是python解释器独有的,存放python解释器自带的名字,如int、float、len

    • 函数调用必须得定义, 从来都没定义过. Python解释器启动的时候python自动开辟内置名称空间存放了这些python的内置方法,python解释器停止解释之后才会销毁

    • 在解释器启动时生效,在解释器关闭时失效

      len([1, 2, 3])
      int('10')
      

    4.1.2 全局名称空间

    • 全局名称空间:除了内置和局部的名字之外,其余都存放在全局名称空间,如下面代码中的x、func、l、z
    • 全局需要自己定义, python文件执行之后才可能有全局名称空间,文件结束之后才会销毁
    x = 1   #  全局名称空间
    
    def func():
        pass
    
    l = [1, 2]    # 内置名称空间
    if 3 > 2:
        if 4 > 3:
            z = 3
    

    4.1.3 局部名称空间

    • 局部名称空间:函数内定义的变量名和函数名都存放在局部名称空间
    • 局部也需要自己定义,必须得在函数调用之后才会生效,调用结束之后就会销毁
    def f1():
        def f2():    # f2为局部名称空间
            print('from f2')
        f2()
    
    f1()
    

    4.1.4 三种名称空间执行顺序

    由于.py文件是由Python解释器打开的,因此一定是在Python解释器中的内置名称空间加载结束后,文件才开始打开,这个时候才会产生全局名称空间,但文件内有某一个函数被调用的时候,才会开始产生局部名称空间,因此名称空间的加载顺序为:内置--》全局--》局部

    4.1.5 三种名称空间查找顺序

    由于名称空间是用来存放变量名与值之间的绑定关系的,所以但凡要查找名字,一定是从三者之一找到,查找顺序为:
    从当前的所在位置开始查找,如果当前所在的位置为局部名称空间,则查找顺序为:局部--》全局--》内置

    x = 1
    y = 2
    len = 100  # 为内置名称空间
    
    def func():
        y = 3
        len = 1000    
        print(f"y: {y}")     # 先在局部内找到y,所以y=3,输出为3
        print(f"len: {len}")   # 先局部内找到len,就不需要再到全局和内置找,因此输出为1000
        # print(a)  # NameError: name 'a' is not defined ,从当前位置到局部再到全局再到内置都没有找到a,所以报错
    
    func()
    

    46名称空间与作用域-简单.png?x-oss-process=style/watermark

    4.2 作用域

    4.2.1 全局作用域

    全局作用域:全局有效,全局存活,包含全局和内置名称空间中的变量,全局作用域中的变量只能在全局中使用

    # 全局作用域
    x = 1
    
    def bar():
        print(x)
    
    bar()
    

    4.2.2 局部作用域

    局部作用域:局部名称空间中的变量只能在局部中使用,局部有效、临时存储,只包含局部名称空间,

    # 局部作用域
    x = 1
    def f1():
       
        print(x)  # f1中的局部
    f1()
    def f2():
        x = 2  # x=2只能在f2中使用
        f1()
    
    f2()  # f1中的局部和f2中的局部互不干涉 
    # 最终输出结果为1
    

    4.2.3 注意点

    作用域关系在函数定义阶段就已经确定死了,与函数的调用无关

    # 作用域注意点
    x = 1
    
    def f1():  # 定义阶段x=1
        print(x)
    
    def f2():
        x = 2
        f1()
    
    f2()
    

    输出结果为1

    lt = [1,2,3]  # 作用域关系仅适用不可变数据类型,不适用于可变数据类型
    
    def f1():
       lt.append(4)
    
    f1()
    
    print(lt)    # [1,2,3,4]
    

    4.2.4 函数对象和作用域应用

    # 作用域应用
    def f1():
        def inner():
            print('from inner')
        return inner
    
    f = f1()  # 把局部定义的函数放在全局之中
    
    def bar():
        f()   # 起到调用函数f1的作用
    
    bar()
    -------------------------------------------------------------------------------
    输出结果为from inner
    

    4.3 补充知识点

    4.3.1 global关键字

    修改全局作用域中的变量

    x = 1
    
    def f1():
        x = 2
    
        def f2():
            #  global x  # 修改全局
            x = 3
        f2()
    
    f1()
    print(x)
    ---------------------------------------------------------------------------------
    
    输出为1
    
    x = 1
    
    def f1():
        x = 2
    
        def f2():
            global x  # 修改全局
            x = 3
        f2()
    
    f1()
    print(x)
    ---------------------------------------------------------------------------------
    输出为3
    

    4.3.2 nonlocal关键字

    修改局部作用域中的变量

    x = 1
    
    def f1():
        x = 2
    
        def f2():
            #         nonlocal x
            x = 3
    
        f2()
        print(x)
    
    f1()
    

    2

    x = 1
    
    def f1():
        x = 2
    
        def f2():
            nonlocal x
            x = 3
    
        f2()
        print(x)
    
    f1()
    

    3

    4.3.3 注意点

    1. 在局部想要修改全局的可变类型,不需要任何声明,可以直接修改。

    2. 在局部如果想要修改全局的不可变类型,需要借助global声明,声明为全局的变量,即可直接修改。

      lis = []
      
      
      def f1():
          lis.append(1)
      
      
      print(f"调用函数前: {lis}")
      f1()
      print(f"调用函数后: {lis}")
      

      调用函数前: []
      调用函数后: [1]

  • 相关阅读:
    2019-2020-20191201《信息安全专业导论》第4周学习总结
    2019-2020-20191201《信息安全专业导论》第3周学习总结
    2019-2020-191201《信息安全专业导论》第二周学习总结
    计算机概论速读提问
    自我介绍
    20191302第六章学习笔记
    20191302反汇编测试
    20191302mystat
    20191302 第五章学习
    20191302 第四章学习笔记
  • 原文地址:https://www.cnblogs.com/zhuangyl23/p/11329829.html
Copyright © 2011-2022 走看看