day16-python-函数对象、函数嵌套、闭包函数

昨日内容回顾

1、名称空间namespaces

    名字-》栈区


    名称空间是对栈的一种划分,真正存在的是栈区,名称空间只是一种虚拟的划分


    内置名称空间(x)

    全局名称空间(x)

    局部名称空间(x)



    重点1:
        名词查找:当前所在的位置向外查找
        局部名称空间->全局名称空间->内置名称空间


    重点2:
        名称空间只有优先级之分,本身并无嵌套关系,画图只是为了理解


    重点3:
        名称空间的嵌套关系决定了名字的查找顺序
        而名称空间的嵌套关系是以函数定义阶段为准的,
        即函数的嵌套关系与名字的查找顺序是在定义阶段就已经确定好的


    x=111
    def f1():
        print(x)
        x=222
    f1()



    全局作用域:内置名称空间+全局名称空间的名字
        全局存活,全局有效

    局部作用域:
        临时存活,局部有效


    nonlocal

今日内容概要

1、函数对象(可以把函数当成变量去用)

2、函数嵌套

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

今日内容详细

精髓:可以把函数当成变量去用
func = 内存地址

def func():
    print('from func')

可以赋值

f = func
print(f, func)
f()

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

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

可以当做函数当做另外一个函数的返回值

def foo(x):  # x=func的内存地址
    return x  # return func的内存地址
res = foo(func)  # foo(func的内存地址)
print(res)  # res=func的内存地址
res()

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

l = [func, ]
# print(l)
l[0]()

dic = {'k1': func}
print(dic)
dic['k1']()

函数对象应用示范

原始版

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


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


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


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


def register():
    print('注册')


func_dic = {
    '1': login,
    '2': transfer,
    '3': check_banlance,
    '4': withdraw,
    '5': register
}

# func_dic['1']()


while True:
    print("""
    0 退出
    1 登录
    2 转账
    3 查询余额
    4 提现
    5 注册
    """)
    choice = input('请输入命令编号:').strip()
    if not choice.isdigit():
        print('必须输入编号,傻叉')
        continue

    if choice == '0':
        break

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

    # if choice == '1':
    #     login()
    # elif choice == '2':
    #     transfer()
    # elif choice == '3':
    #     check_banlance()
    # elif choice == '4':
    #     withdraw()
    # else:
    #     print('输入的指令不存在')

修正版

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


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


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


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


def register():
    print('注册')


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


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

    # choice='1'
    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):
    # 第一步:比较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)

函数的嵌套定义: 在函数内定义其他函数

def f1():
    def f2():
        pass


# 示范
# 求圆形的求周长:2*pi*radius
def circle(radius, action=0):
    from math import pi

    def perimiter(radius):
        return 2*pi*radius

    # 求圆形的求面积:pi*(radius**2)
    def area(radius):
        return pi*(radius**2)

    if action == 0:
        return 2*pi*radius

    elif action == 1:
        return area(radius)


circle(33, action=0)

闭包函数

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

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

闭包函数:名称空间与作用域的应用+函数嵌套
def f1():
    x = 33333333333333333333

    def f2():
        print(x)
    f2()


x = 11111


def bar():
    x = 444444
    f1()


def foo():
    x = 2222
    bar()


foo()

闭包函数:函数对象

def f1():
    x = 33333333333333333333

    def f2():
        print('函数f2:', x)
    return f2


f = f1()
# print(f)

# x=4444
# f()


def foo():
    x = 5555
    f()


foo()

闭包函数的应用

两种为函数体传参的方式

方式一:直接把函数体需要的参数定义成形参

def f2(x):
    print(x)


f2(1)
f2(2)
f2(3)

方式二:通过闭包函数的方式

def f1(x):  # x=3
    x = 3

    def f2():
        print(x)
    return f2


x = f1(3)
print(x)

x()

传参的方案一:

def get(url):
    response = requests.get(url)
    print(len(response.text))


get('https://www.baidu.com')
get('https://www.cnblogs.com/linhaifeng')
get('https://zhuanlan.zhihu.com/p/109056932')

传参的方案二:

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/linhaifeng')
cnblogs()

zhihu = outter('https://zhuanlan.zhihu.com/p/109056932')
zhihu()

作业

今日作业:
    1、函数对象优化多分支if的代码练熟
    2、编写计数器功能,要求调用一次在原有的基础上加一
        温馨提示:
            I:需要用到的知识点:闭包函数+nonlocal
            II:核心功能如下:
                def counter():
                    x+=1
                    return x


        要求最终效果类似
            print(couter()) # 1
            print(couter()) # 2
            print(couter()) # 3
            print(couter()) # 4
            print(couter()) # 5


# ====================周末作业====================
# 编写ATM程序实现下述功能,数据来源于文件db.txt
# 0、注册功能:用户输入账号名、密码、金额,按照固定的格式存入文件db.txt
# 1、登录功能:用户名不存在,要求必须先注册,用户名存在&输错三次锁定,登录成功后记录下登录状态(提示:可以使用全局变量来记录)

下述操作,要求登录后才能操作
# 1、充值功能:用户输入充值钱数,db.txt中该账号钱数完成修改
# 2、转账功能:用户A向用户B转账1000元,db.txt中完成用户A账号减钱,用户B账号加钱
# 3、提现功能:用户输入提现金额,db.txt中该账号钱数减少
# 4、查询余额功能:输入账号查询余额
原文地址:https://www.cnblogs.com/zdw20191029/p/14553356.html