• 11.函数对象,函数嵌套,名称空间与作用域,闭包函数


    • 引子
    • 函数对象

    • 函数嵌套

    • 名称空间与作用域

    • 闭包函数


    • 函数对象

    在python中,函数是第一类对象,即函数可以当做数据传递,函数又称第一等公民

    本质:函数可以当变量用

    • 1.可以赋值
    def func(): # func = 函数的内存地址
        print('from func')
    
    f = func   # func 可以赋值给其它变量
    print(f)
    f()
    
    • 2.可以当做参数传给另外一个函数
    def func(): 
        print('from func')
        
    def foo(x):
        print(x)
        x()      # 可以加()触发内部代码的运行
    foo(func)
    
    • 3.可以当做函数的返回值
    def func(): 
        print('from func')
        
    def foo(x):        # 把func丢进去
        return x       # 紧接着又扔出来func
     
    res = foo(func)
    print(res)
    
    • 4.可以当做容器类型的元素
    def func():
        print('from func')
        
    l = [func,]  # 列表调用
    print(l)
    l[0]()
    
    
    # 容器类型的元素的应用
    # 购物车程序
    
    def withdraw():
        print("提款")
        
    def tranfer():
        print("转账")
        
    def check_balance():
        print("查询余额")
        
    def save():
        print("存款")
      
    func_dic = {
        "1":["提款",withdraw],
        "2":["转账",tranfer],
        "3":["查询余额",chenk_balance],
        "4":["存款",save]
    }
    
    while True:
        print("0 退出")
        for k,v in func_dic.items():
            print(k,v[0])
            
        choice = input("请输入您要操作的编号>>>:").strip()
        if choice == '0':
            break
        if choice in func_dic:
            func_dic[choice][1]()
        else:
            print("输入错误")
    
    • 函数嵌套

    • 函数的嵌套调用
    def max2(x,y):   # 比较两个值的大小
        if x > y:
            return x
        else:
            return y
        
    def max4(a,b,c,d):  # 求四个值的最大值
        res1 = max2(a,b)
        res2 = max2(res1,c)
        res3 = max2(res2,d)
        return res3
    
    print(max4(11,99,33,12))
    # 把一个大功能拆解成几个小功能,然后再把每个小功能分别去实现,最后在拼接回来
    
    • 函数的嵌套定义
    def f1():
        x = 10           # 变量丢到函数里面是一个封闭的效果
        def f2():
            print('from f2')
        print(x)         #1 这两行代码是站在内部去看的可以看见
        print(f2)        #2
    f1()
    print(x)          #1 这两行代码是站在外面去看的是看不见的
    print(f2)         #2
    # 函数层级带来的变量访问的限制,到底是因为什么?定义在某一个位置的东西到底在哪才能看得见?
    
    • 名称空间与作用域

    • namespaces名称空间:存放名字的地方

      内置名称空间:存放内置的名字
      生命周期:python解释器启动则产生,关闭则销毁
      全局名称空间:存放的是顶级的名字
      生命周期:运行python文件时则产生,python文件运行完毕则销毁
      局部名称空间:存放的是函数内的名字
      生命周期:调用函数则产生,函数调用完毕则销毁
    # 内置名称空间:
    >>> input
    <built-in function input> # built-in 内置
    
    # 全局名称空间:
    x = 10    # 变量名X
    y = 20    # 变量名y
    f 1 > 0:
        z = 30
        
    with open('a.txt', mode='wt') as f:
        a = 333
        
    while True:
        c = 444
    # 以上都是属于顶级的
    
    # 局部名称空间:
    x = 10        # 全局名称空间
    def foo(m):   # 全局名称空间
        m = 111   # 调用函数时,才会执行函数代码,名字m和n都存放于该函数的局部名称空间中
        n = 222   # 函数内
    foo(111)      # 调用产生函数名称空间
    
    名称空间的加载顺序是:内置名称空间--->全局名称空间--->局部名称空间
    而查找一个名字,必须从三个名称空间之一找到
    查找顺序为:局部名称空间--->全局名称空间--->内置名称空间
    核心:名字的访问优先级
    基于当前所在的位置向外查找
    # 案例1
    len = 10  # 全局名称空间
    
    def func(): # 函数
        len = 20
        # print(len)  # 站在局部查找,找到的是20
        
    func()      # 调用产生局部名称空间
    print(len)  # 站在全局找,全局有找全局,全局没有找内置
    
    # 案例2
    def f1():
    	x = 555
    	def f2():
    		x = 666
    		print(x)
    	f2()
    x = 444
    f1()
    
    • 作用域(******)

      名称空间与作用域的关系是在函数定义阶段(扫描语法时)就确立的,
      与什么时候调用以及调用位置无关
    x = 111
    def f1():
        print(x)
        
    def f2():
        x = 222
        f1()
        
    f2()
    
    
    # 案例2
    x = 111
    def f1():
        print(x)
        x = 222
    f1()
    
    • 作用域

      全局作用域:内置名称空间 + 全局名称空间

      特点:全局存活(除非被删除,否则在整个文件执行过程中存活)

      全局有效(在任意位置都可以使用)

      局部作用域:局部名称空间

      特点:临时存活(即在函数调用时临时生成,函数调用结束后就释放)

      局部有效(只能在函数内使用)

    • global关键字

      ​ 在函数内,无论嵌套多少层,都可以查看到全局作用域的名字,若要在函数内修改全局名称空间中名字的值,当值为不可变类型时,则需要用到global关键字

    # 案例1:
    l = []
    def func():
        l.append(1111)
       # l = [11,22,33]
    func()               # 调func执行append
    print(l)
    # 当全局变量是可变类型的时候,局部是可以直接改的
    
    # 案例2:
    x = 111   # 全局变量不可变类型
    def func():   
        global x  # 声明X是属于全局的,是可以改变的      
        x = 222   # 在局部产生新的名字不影响全局
    func()
    print(x)
    # 要想在局部修改一个全局的不可变类型,可以用global修改
    
    • nonlocal关键字

      对于嵌套多层的函数,使用nonlocal关键字可以将名字声明为来自外层嵌套函数定义的作用域(非全局)

    x = 111
    def f1():
       # x = 222
        def f2():
           # global x   # 声明变量名是来自全局的
            nonlocal x  # 声明变量名是来自于外层函数的,不是全局
            x = 333   # 要想在这个位置用global把x=222改掉不可能
        f2()
        print(x)
        
    f1()
    

    • 闭包函数

      闭:指的该函数是定义在函数内的函数

      包:指的就是该函数引用了一个外层函数作用域的名字(e作用域的名字)

    def outter():
        x = 111      # 为wrapper函数的函数体代码传参
        def wrapper():  
            print(x)
    # 以后无论wrapper在哪调,它访问的x以定义阶段为准。
            
    def outter():  # outter最外层函数
        x = 111
        def wrapper():  # 把wrapper闭到了outter里面了,wrapper就只能在里面用
            print(x)        
        return wrapper  # 千万别加括号,要想把wrapper从里面扔出来用就需要用return
    f = outter()  # 把一个内部函数扔到全局,这个内部函数就打破了层级限制,可以在任意位置调用
    print(f)
    
    def foo():
        x = 222
        f()   # 此时调f就相当于调wrapper
        
    foo()
    
    • 为函数代码体传参的方案

    方案一:直接用参数传
    def wrapper(x):
        print(x)
        
    wrapper(111)
    wrapper(222)
    wrapper(333)
    
    方案二:闭包函数
    def outter(x):       # 为了给wrapper函数传参只能把它扔进去,wrapper本来是顶级的
        def wrapper():
            print(x)
        return wrapper   # 参数传完就把wrapper用return扔出去
    
    f1 = outter(111)    # 再想拿到wrapper,调outter拿到返回值,f1相当于当初的wrapper
    f1()
    
    f2 = outter(222)
    f2()
    
  • 相关阅读:
    mysql 分列或取子串
    Excel “20200504”文本格式转化为时间格式
    Mysql清空数据表
    python 做词云图
    Pandas操作excel
    python中zip()函数的用法
    Excel技能提升
    JS 学习笔记
    元类理解与元类编程 《Python3网络爬虫开发》中第九章代理的使用代码Crawler中代码的理解
    关于选择器注意的点
  • 原文地址:https://www.cnblogs.com/gfeng/p/14208533.html
Copyright © 2020-2023  润新知