zoukankan      html  css  js  c++  java
  • 闭包

    1. 函数对象

    精髓: 可以把函数当成变量去用

    函数名和变量名一样,都是指向的是内存地址

    2. 函数名的用途

    2.1 可以赋值

    把一个函数名赋值给另一个变量名

    # func=函数的内存地址
    def func():
        pass
    
    f=func        
    print(func)   # <function func at 0x000001E78F9B3EA0> 
    print(f)      # <function func at 0x000001E78F9B3EA0>
    

    2.2 当参数

    函数名也可以当做参数传给另一个函数

    def func():
        pass
    
    def foo(×):  #× = func的内存地址#
        print(x)
        x()
    
    foo(func)  #foo( func的内存地址)
    

    2.3 当返回值

    函数名也可以当做函数的返回值

    def func():
        pass
    
    def foo(x):
        return x    
    
    
    res = foo(func)
    print(res)
    

    2.4 当参数

    函数名可以当做容器类型的一个元素

    def func():
        print('func函数: ',func)
        
    l=[func,]
    print(l)
    l[0]()        # 调用func函数
    dic={ 'k1' :func}
    print(dic)
    dic['k1']()  # 调用func函数
    

    2.5 小练习

    def login():
        print('登录功能')
    
    
    def transfer():
        print('转账功能')
    
    
    def check_balance():
        print('查询余额')
    
    
    def change_password():
        print('修改密码')
    
    
    # 巧用数据类型
    dic = {
        # '1': login,
        '0': ('退出', None),
        '1': ['登录', login],
        '2': ['转账', transfer],
        '3': ['查询余额', check_balance],
        '4': ['更改密码', change_password],
        # '2': transfer,
        # '3': check_balance,
    }
    
    while 1:
        for key, value in dic.items():
            print('{} {}'.format(key, value[0]))
        choice = input('请输入编号:').strip()
        if not choice.isdigit():
            print('必须输入编号,憨批')
            continue
        if choice == '0':
            break
        if choice in dic:
            dic[choice][1]()
        else:
            print('你输入的命令不存在,憨批')
    

    3. 函数的嵌套

    3.1 函数的嵌套调用

    在调用一个函数的过程中又调用其他的函数

    def func1():
        print("调用了func1函数")
        
    def func2():
        print("调用了func2函数")
        
    def func3():
        print("调用了func3函数")
        
        
    def func():
        func1()
        func2()
        func3()
    

    应用场景 :

    # 把各个小功能(小函数),封装到一个大功能(大函数)里面
    
    def max2(x, y):
        return x if x > y else y
    
    
    # 比较4个参数的大小
    def max4(a, b, c, d):
        # 比较a,b得到res1
        res1 = max2(a, b)
        # 比较res1,c,得到res2
        res2 = max2(res1, c)
        # 比较res2,d ,得到res3
        res3 = max2(res2, d)
        return res3
    
    
    print(max4(7838237, 9859, 949, 90))
    

    3.2 函数的嵌套定义

    在函数内定义其他的函数

    def func():
        def func1():
            pass
    
    # 举例:
    # 求圆的周长和面积,但是只在圆内调用,在其他地方不用
    from math import pi
    
    
    def circle(radius, action=None):
        "radius:半径 action为0是求周长 action为1是求面积 "
    
        def get_perimeter(radius):
            return 2 * radius * pi
    
        def get_area(radius):
            return pi * radius ** 2
    
        # 求圆的周长
        if action == 0:
            return get_perimeter(radius)
        # 求圆的面积
        elif action == 1:
            return get_area(radius)
    

    上面的应用场景比较少,函数的嵌套定义更多的用在闭包

    # 函数的嵌套定义你可以认为把一堆函数丢到一个大容器(最外面的那个函数)中
    # 同时在外部是无法访问这个函数的,只能在大容器中访问这些函数
    

    4. 闭包函数

    闭包函数也可以直接简称为闭包

    # 闭包函数 = 名称空间与作用域 + 函数嵌套 + 函数对象
    # 核心点: 名字的查找关系是以函数定义阶段为准
    

    4.1 什么是闭包函数

    # "闭"函数指的是该函数为内嵌函数         是定义在一个函数内的函数
    
    def f1():
        def f2():   # f2是闭函数
            pass
    
    # "包是在闭的基础上"
    # "包"函数指的该函数包含对外层函数(第几层无所谓)作用域名字的引用(不是对全局作用域)
    
    def f1():
        x = 111
        def f2():
            print(x)    # x就是包,f2从外层函数f1那里引用
    

    闭包函数 : 名称空间与作用域 + 函数嵌套

    def f1():
        x = 222
    
        def f2():
            print(x)
    
        f2()
    
    
    x = 111
    
    
    def foo():
        x = 333
        f1()
    
    
    foo()    # 打印2222
    

    闭包函数 : 名称空间与作用域 + 函数嵌套 + 函数对象

    def f1():
        x = 33333333333333333333
    
        def f2():
            print('函数f2:', x)
    
        return f2   # 这样一搞就有了骚操作,在全局能够访问到f2的内存地址了,就打破了
    				# 以前在外部无法访问局部的值了
    
    
    f = f1()
    
    
    # f是全局的,但是f的值是局部的
    # 牛逼之处你在全局拿到了在局部作用域的名字
    # 牛逼的实现了,在任意地方都能访问到局部的值了,打破了层级限制
    # 拖家带口的返回,每次你调用里面的x都是在局部定义的那个x
    

    4.2 为什么要有闭包

    为什么要有闭包换句话说就是闭包的应用场景有哪些?

    闭包实现了函数的另一种传参方式,虽然没有直接传参那种看上去更加简单,但是有的应用场景就是直接传参

    解决不了,那么你不要忘记还有一种闭包传参的方式

    # 先写x=3和函数f2的定义,然后用f1包起来
    def f1():
        x = 3
    
        def f2():
            print(x)
    
        return f2
    
    f = f1() #此时f指的就是f2的内存地址
    # 你可以写f,那么你也可以写成f2
    # f2 = f1()
    
    # 有的人就说了 你写成x=3不是写死了吗,那么我们可以这样写
    def f1(x):
        def f2():
            print(x)
    
        return f2
    
    # f = f1(1)
    # f = f1(2)
    # f = f1(3)  # 这样就做到了 你传几,就是几
    

    5. 两种传参方式

    一种就是直接传 还有一种就是通过闭包传

    学习闭包就是学习了另一种函数传参方式,(曲线救国),当你有一中需求是函数直接

    传参解决不了的时候,不要忘记还有闭包这种这种传参方式,下面介绍的装饰器就是

    你无法直接传参,只能通过闭包传参来解决

  • 相关阅读:
    常用类练习题(用字符串常用类判断输入的一段话是否为回文)
    面向对象综合练习题(动物乐园)
    多态练习题(通过UML建模语言来实现饲养员喂养动物)
    UML建模语言使用的概述
    多态练习题(员工使用不同的交通工具回家)
    多态练习题(宠物医院治疗小动物的问题 ,多态的应用:向上类型传递)
    接口练习题(书信接口)
    接口练习题(实现接口功能拓展的两种方法)
    Oracle rman 各种恢复
    Oracle rman 全备份的一个小例子
  • 原文地址:https://www.cnblogs.com/xcymn/p/14038928.html
Copyright © 2011-2022 走看看