函数高阶应用与闭包

函数高阶应用与闭包

函数对象

 

  将函数看做一个对象可以做以下的事情:   

    1.可以赋值   

    2.可以把函数当做参数传入另一个函数   

    3.可以将内层函数当做外层函数的返回值   

    4.可以将函数当做容器类型中的一个元素

 

# ==== 可以赋值 ====
def func():
    print("function func...")
​
​
# func是指向的是一个函数内存地址 <function func at 0x000001AE33574040>
# 如果带上括号则代表是函数func执行后return的结果
​
f1 = func
f1()
​
# ==== 执行结果 ====
"""
function func...
"""
# ==== 可以把函数当做参数传入另一个函数 ====
def foo(func):
    func()
​
​
def bar():
    print("function bar..")
​
​
foo(bar)  # 代表将bar指向的函数内存地址传入。
# ==== 执行结果 ====
"""
function bar..
"""
# ==== 可以将内层函数当做外层函数的返回值 ====
def outer():
    def inner():
        print("function inner...")
​
    return inner
​
​
func = outer()  # outer 执行,返回inner指向的函数内存地址。被变量名func接收
func()  # func指向一个函数内存地址,加括号代表执行函数
# ==== 执行结果 ====
"""
function inner...
"""
# ==== 可以将函数当做容器类型中的一个元素 ====
def f1():
    print("function f1...")
​
​
def f2():
    print("function f2...")
​
​
def f3():
    print("function f3...")
​
​
li = (f1, f2, f3)
for func in li:  # 每次循环取出一个函数的内存地址。加括号代表执行
    func()
​
# ==== 执行结果 ====
"""
function f1...
function f2...
function f3...
"""

函数对象的常见应用场景

# ==== 信息修改 ====
​
stumsg = {
    "1": {"name": "Yunya", "gender": "male", "age": 18, "height": 192, "weight": 140},
    "2": {"name": "Jack", "gender": "male", "age": 17, "height": 172, "weight": 120},
    "3": {"name": "Xiaohua", "gender": "female", "age": 20, "height": 168, "weight": 130},
}
​
​
def check():
    """"""
    for item in stumsg:
        print("学生编号:{0}".format(item))
        for k, v in stumsg[item].items():
            print("{0: >10} | {1: <10}".format(k, v))
    input("按任意键退出当前功能")
​
def change():
    """"""
    while 1:
        num = input("请输入学生编号或者按q退出:").strip()
        if num == "q":
            breakif num not in stumsg:
            print("请重新输入")
            continue
        elif num.isdigit() and num in stumsg:
            item = {}
            k = input("请输入修改的选项:")
            v = input("请输入修改的值:")
            item[k] = v
            if k in stumsg[num]:
                stumsg[num].update(item)
                print("修改成功。当前该学生信息为:{0}".format(stumsg[num]))
            else:
                print("修改信息不合法")
        else:
            print("输入有误,重新输入")
            continue
​
​
def delete():  """"""
    print("功能待完善..")
​
​
def add():  """"""
    print("功能待完善..")  # 后期想添加功能只需要在show里面添加即可。
​
​
show = {
    "1": ["查看学生信息", check],
    "2": ["修改学生信息", change],
    "3": ["删除学生信息", delete],
}
​
while 1:
    print("{0:=^20}".format("欢迎登陆学生管理系统"))
    for k, v in show.items():
        print(k, v[0])
    print("*"*20)
    select = input("请输入您的选项或者按q退出:").strip()
​
    if select == "q":
        breakif select not in show:
        continue
    elif select.isdigit() and select in show:
        show[select][1]() # 拿到函数内存地址,加括号代表执行。
    else:
        print("输入有误请重新输入")
        continue 

 

函数嵌套调用

 

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

  作用:让代码可读性增强。一个函数负责提供接口,一个函数负责逻辑处理

 

def contrastReturn(x,y):  
    """逻辑处理函数"""
    if x > y:
        return x
    else:
        return y
​
def contrastMax(a,b,c,d):
    """比较,返回最大值,接口函数"""
    # 第一步,比较 a,b 得到res1
    # 第二步,比较res1与c的大小。得到res2
    # 第三步,得到res2与d比较。返回最终结果
    res1 = contrastReturn(a,b)
    res2 = contrastReturn(res1,c)
    res3 = contrastReturn(res2,d)
    return res3
​
print(contrastMax(1,2,3,4))
​
# ==== 执行结果 ====
"""
4
"""

 

基于函数的封装

 

  定义:在函数内部定义函数。

  作用:在函数内部定义的函数不能被全局作用域所访问。所有变量名存储在局部命名空间中不与内置命名空间与全局命名空间的名字发生冲突。

 

def mathformula(select, length, width, height=None):
    """长方形,求面积输入长宽,求体积输入长宽高"""def area(length, width):
        """长方形面积"""
        return length * width
​
    def bulk(length, width, height):
        """长方体体积"""
        return length * width * height
​
    if select == 1:
        return area(length, width)
    elif select == 2:
        return bulk(length, width, height)
    else:
        print("输入有误")
​
​
res = mathformula(select=1,length=20,width=20)
print(res)
​
# ==== 执行结果 ====
"""
4
"""

 

闭包函数

 

  闭包函数 = 命名空间与作用域 + 函数嵌套 + 函数对象 结合体

  核心点:名字的查找顺序以定义阶段为标准。当前命名空间没找到名字时往定义自己的命名空间查找名字。

 

  “闭”函数指的是该函数定义在另一个函数体中

  “包”函数指的是该内嵌函数包含对外层函数作用域名字的引用(不是对全局作用域,而是对定义内嵌函数名字的那一层函数局部命名空间中名字的引用)

 

# ==== 闭包函数的使用 ====
​
x = "全局命名空间中的变量值"
def outer():
    x = "outer局部命名空间中的变量值"
    def inner():
        print(x) # inner局部命名空间中没有,往定义自己名字的命名空间查找。outer
    return inner # 返回一个内存地址。也就是内部函数inner的内存地址
​
res = outer() # res 等于 inner
res() # 相当于执行inner函数
# ==== 执行结果 ==== Ps:不管是从哪里执行的inner函数,inner中引用的x始终是属于outer外层函数局部命名空间中的的x
"""
outer局部命名空间中的变量值
"""
# ==== 闭包函数的使用 ====
​
x = "全局命名空间中的变量值"
def outer():
    x = "outer局部命名空间中的变量值"
    def inner():
        print(x) # inner局部命名空间中没有,往定义自己名字的命名空间查找。outer
    return inner # 返回一个内存地址。也就是内部函数inner的内存地址
def foo():
    x = "foo局部命名空间中的变量值"
    res = outer() # res 等于 inner
    res() # 相当于执行inner函数
​
foo()
​
# ==== 执行结果 ====
"""
outer局部命名空间中的变量值
"""

 

闭包函数的作用

 

  在某些情况下我们需要使用闭包函数为内部函数进行参数的传递。这是闭包函数的作用之一,另一作用就是在不修改原本上线的功能函数内部代码以及不修改其调用方式前提下为其增添新的功能,

  Ps:在闭包函数中,外层的封装函数命名空间中所有的变量都不会被销毁。

 

# 在不修改源代码及调用方式的情况下为download函数添加一个计算程序运行时间的功能
import time
import random
​
def download():
    # 通过time模块和random模块模拟下载功能
    print("正在下载...")
    time.sleep(random.randint(1,3)) # time.sleep()为睡眠,暂停执行。random为生成随机数
    print("下载完成...")
​
download()
​
# ==== 执行结果 ====
"""
正在下载...
下载完成...
"""

最终方案(使用闭包函数进行解决)

import time
import random
​
​
def download():
    # 通过time模块和random模块模拟下载功能
    print("正在下载...")
    time.sleep(random.randint(1, 3))
    print("下载完成...")
​
def outer(func):
    def inner():
        start = time.time() # time.time()为记录当前时间
        func() # inner局部命名空间没有,向上查找。拿到func再进行执行。
        end = time.time()
        print("函数运行时间是:{:.2f}秒".format(end - start)) # 结束时间减去开始时间
return inner
​
download = outer(func=download) # 将download用方式的形式把函数内存地址传入
download() # 看似在调用 download,实际上是调用inner
# ==== 执行结果 ===
"""
正在下载...
下载完成...
函数运行时间是:2.00秒
"""
原文地址:https://www.cnblogs.com/Yunya-Cnblogs/p/12895266.html