Python 函数对象与闭包函数

20 阅读4分钟

一、函数对象

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

# func = 内存地址
def func():
    print('from func')
  1. 可以赋值,其实传的是内存地址

    def func():
        print('from func')
    
    
    f = func
    print(f, func)
    # <function func at 0x0000016130DF6160> <function func at 0x0000016130DF6160>
    
  2. 可以把函数当做传给另外一个函数的参数,其实传的是内存地址

    def func():
        print('from func')
    
    
    def foo(x):  # x = func的内存地址
        print(x)
        x()
    
    
    foo(func)  # foo(func的内存地址)
    # 运行结果
    # <function func at 0x0000022AD65D6160>
    # from func
    
  3. 可以把函数当做另外一个函数的返回值,其实传的是内存地址

    def func():
        print('from func')
    
    
    def foo(x):  # x=func的内存地址
        return x  # return func的内存地址
    
    
    res = foo(func)  # foo(func的内存地址)
    print(res)  # res=func的内存地址
    
    res()  # func()
    # 运行结果
    # <function func at 0x0000022AD65D6160>
    # from func
    
  4. 可以当做容器类型的一个元素,其实传的是内存地址

    def func():
        print('from func')
    
    
    l = [func, ]
    print(l)  # [<function func at 0x000001EB234F6160>]
    l[0]()  # from func
    
    dic = {'k1': func}
    print(dic)  # {'k1': <function func at 0x000001EB234F6160>}
    dic['k1']()  # from func
    

函数对象应用示范:

# 功能函数

def login():
    print('登录功能')

def transfer():
    print('转账功能')

def check_banlance():
    print('查询余额')

def withdraw():
    print('提现功能')

def register():
    print('注册功能')
# 用户输入编号,执行对应功能

while True:
    print("""
    0 退出
    1 登录
    2 转账
    3 查询余额
    4 提现
    5 注册
    """)
    choice = input('请输入命令编号:').strip()
    if not choice.isdigit():
        print('必须输入编号,傻叉')
        continue
    if choice == '0':
        break
    if choice == '1':
        login()
    elif choice == '2':
        transfer()
    elif choice == '3':
        check_banlance()
    elif choice == '4':
        withdraw()
    else choice == '5':
        register()
    else:
        print('输入的指令不存在')

如果有100个功能,就要写100个判断语句吗?

# 使用字典纳入所有功能,利用函数对象知识进行判断结构的优化

func_dic = {
    '0': ['退出', None],
    '1': ['登录', login],
    '2': ['转账', transfer],
    '3': ['查询余额', check_banlance],
    '4': ['提现', withdraw],
    '5': ['注册', register]
}
while True:
    for k in func_dic:
        print(k, func_dic[k][0])

    choice = input('请输入命令编号:').strip()
    if not choice.isdigit():
        print('必须输入编号,傻叉')
        continue

    if choice == '0':
        break

    if choice in func_dic:
        func_dic[choice][1]()
    else:
        print('输入的指令不存在')

二、函数的嵌套使用

  1. 函数的嵌套调用:在调用一个函数的过程中又调用其他函数

    def max2(x, y):
        if x > y:
            return x
        else:
            return y
    
    
    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
    
    
    res = max4(1, 2, 3, 4)
    print(res)
    
  2. 函数的嵌套定义:在函数内定义其他函数

    def fun1():
        def fun2():
            pass
    
    # 求圆形的周长,面积
    
    def circle(radius):
        from math import pi
        
        # 求圆形的求周长:2*pi*radius
        def girth(radius):
            return 2 * pi * radius
    
        # 求圆形的求面积:pi*(radius**2)
        def area(radius):
            return pi * (radius ** 2)
    
        print('周长为:', girth(radius))
        print('面积为:', area(radius))
    
    
    radius = float(input('请输入半径:'))
    circle(radius)
    

三、闭包函数

  1. 大前提

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

    核心点:==名字的查找关系是以函数定义阶段为准==

  2. 什么是闭包函数

    "闭 "函数:指该函数是内嵌函数

    "包 "函数:指该函数包含对外层函数作用域名字的引用(不是对全局作用域)

    def f1():
        x = 33333333333333333333
    
        def f2():
            print(x)
    
        f2()
    
    
    f1()  # 33333333333333333333
    

    f2函数就是一个闭包函数。如果将print(x)去掉,则f2函数就只是一个闭函数。

    名称空间与作用域的应用+函数嵌套+函数对象
    def f1():
        x = 33333333333333333333
    
        def f2():
            print('函数f2:', x)
    
        return f2
    
    
    f = f1()
    
    
    def foo():
        x = 5555
        f()
    
    
    foo()  # 函数f2: 33333333333333333333
    
  3. 为什么要有闭包函数(闭包函数的应用)

    目前为止,我们得到了两种为函数体传值的方式,一种是直接将值以参数的形式传入,另外一种就是将值包给函数。

    方式一:直接把函数体需要的值定义成形参
    def f1(x):
        print(x)
    
    f1(1)
    f1(2)
    f1(3)
    
    方式二:利用闭包函数的原理
    def f1(x):  # x=3
        def f2():
            print(x)
    
        return f2
    
    
    res = f1(3)
    print(res)  # <function f1.<locals>.f2 at 0x00000200A7826160>
    
    res()  # 3
    

    应用

    requests模块是用来模拟浏览器向网站发送请求,并将页面内容下载到本地(requests.get().text)。

    应用方式一进行:
    import requests
    def get(url):
        response = requests.get(url)
        print(len(response.text))
    
    
    get('https://www.baidu.com')
    get('https://www.cnblogs.com')
    get('https://www.zhihu.com')
    
    应用方式二进行:
    import requests
    def outter(url):
        # url='https://www.baidu.com'
        def get():
            response = requests.get(url)
            print(len(response.text))
    
        return get
    
    baidu = outter('https://www.baidu.com')
    baidu()
    
    cnblogs = outter('https://www.cnblogs.com')
    cnblogs()
    
    zhihu = outter('https://www.zhihu.com')
    zhihu()
    
    学习闭包函数,就是掌握了一种“变相传参”的方法,这种方法在后面的装饰器知识中会再次出现。