函数对象与闭包

一、函数对象

函数对象指的是函数可以被当做‘数据’来处理,

函数名不加括号就是指函数的内存地址
函数名加括号,就是调用函数,找到函数体代码并执行,不论在哪个位置

def index():
    print('from index')
print(index)  # <function index at 0x0000016EE3462F28>

具体可以分为四个方面的使用,我们如下

1.1 函数名可以当成变量赋值

def index():
    print('from index')
a = index
a()  # => index(),也可以调用函数
print(a)  # <function index at 0x0000013E4FA92F28>

1.2 函数名可以当成函数的实参

# 2.1 只打印a
def index():
    print('from index')
def func(a):
    print(a)  # a => index
    print('from func')
func(index)
# 输出结果是:
# <function index at 0x0000021506D82F28>
# from func

# 2.2 运行了a()
def index():
    print('from index')

def func(a):
    print(a)  # a => index
    a()
    print('from func')
func(index)
# 输出结果是:
# <function index at 0x0000024D40F12F28>
# from index
# from func

# 2.3 错误
def index():
    print('from index')

def func(a):
    a()
    print('from func')
# 将函数的返回值当成了参数,但是index的返回值是空,会报错
# func(index())  # 填入的是None,不能运行,会报错

1.3 函数名可以当成函数的返回值

def index():
    print('from index')

def func():
    print('from func')
    return index  # 返回的就是index函数的内存地址

res=func()  # res就是index函数的内存地址
print(res)
res()
# 输出结果是:
# from func
# <function index at 0x0000017630372F28>
# from index

1.4 函数名可以当成容器类型的元素

def index():
    print('from index')

    return 'from a'

l = [11, 22, 33, index]  # 函数index并没有调用,不会返回'from index'
print(l)
l1 = [11, 22, 33, index()] # index()出现,函数被调用
print(l1)
# 输出结果是:
# [11, 22, 33, <function index at 0x000002187F9B2F28>]
# from index
# [11, 22, 33, 'from a']

1.5 小练习:优化登录注册功能

用之前所学知识写出:

def register():
    print('注册')
def login():
    print('登录')
def transfer():
    print('转账')
def shopping():
    print('购物')
def withdraw():
    print('提现')

while True:
    print("""
        1. 注册
        2. 登录
        3. 转账
        4. 购物
        5. 提现
    """)
    choice = input('请输入编号:').strip()
    if choice == '1':
        register()
    elif choice == '2':
        login()
    elif choice == '3':
        transfer()
    elif choice == '4':
        shopping()
    else:
        print('没有改功能')

这种方式比较繁琐,这是只有5个功能,如果有50个功能,用这种方式更加繁琐,或者想要增加一个功能需要改变的步骤太多。

以下是用新方法改的代码:
直接使用字典,将函数名与序号组成键值对形式写入字典中。

'''函数名只要加括号,就会执行!!!!!!!!!'''
def register():
    print('注册')
def login():
    print('登录')
def transfer():
    print('转账')
def shopping():
    print('购物')
def withdraw():
    print('提现')
def chongzhi():
    print('cz')

func_dict = {
    '1': register,
    '2': login,
    '3': transfer,
    '4': shopping,
    '5': withdraw,
    '6': chongzhi,
}

while True:
    print("""
        1. 注册
        2. 登录
        3. 转账
        4. 购物
        5. 提现
        6. 充值
    """)
    choice = input('请输入编号:').strip()
    # 判断用户输入的编号在不在fund_dict这个字典里面
    if choice in func_dict:
        func_name = func_dict.get(choice)  # 函数的内存地址
        func_name()
        # 上面两行代码可以简写
        # func_dict.get(choice)()
    else:
        print('不存在')

二、函数的嵌套调用

2.1 在函数内部定义函数

def index():
    print('from index')
    print('111')
    print('222')
    print('333')

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

func()
# 输出结果是:
# from index
# 111
# 222
# 333
# from func

练习1:判断两个数的大小

判断两个数的大小
有两种不同的写法:

写法1:

def my_max(a, b):
    if a > b:
        return a
    else:
        return b
res = my_max(2, 3)
print(res)  # 3

写法2:
这种方法更高级一点

def my_max(a, b):
    if a > b:
        return a
    return b
res = my_max(70, 5)
print(res)  # 70

练习2:判断4个数的大小

判断4个数的大小,返回大的

# 2.1 先写出一个函数判断两个数的大小
def my_max(a, b):
    if a > b:
        return a
    return b

def many_max(a, b, c, d):
    res = my_max(a, b)  # b
    res1 = my_max(res, c)
    res2 = my_max(res1, d)
    return res2

ret = many_max(1, 2, 3, 4)
print(ret)

2.2 函数嵌套

# 把复杂的功能隐藏起来,暴露给外界一个简单的接口
def all_func(type):

    def register():
        pass
    def login():
        pass
    def shopping():
        pass
    def transfer():
        pass

    if type == '1':
        register()
    elif type == '2':
        login()
    elif type == '3':
        shopping()
    elif type == '4':
        transfer()
    else:
        print('不存在')

print('''
    1.登录
    2.注册
    3.购物
    4.转账
''')
choice = input('请输入你选择的序号:>>>')
all_func(choice)
# 当输入1时,就会执行注册功能,输入2时,就会执行登录功能...

二、闭包函数

闭:定义在函数内部的函数
包:内部函数使用外部函数名称空间中的名字
'''只有同时满足以上两个条件的函数,才是闭包函数'''

2.1 概念

# 1.函数变量定义在外面,func不是闭包函数,它符合闭不符合包
x = 100
def index():
    def func():
        print(x)
    return func
index()
print(index())  # <function index.<locals>.func at 0x000002683136ED08>


# 2.是闭包函数
def index():
    x = 100
    def func():
        print(x)
    return func
index()
print(index())  # <function index.<locals>.func at 0x000002683136ED08>

2.2 作用

闭包函数的作用就是:第二种传参的方式

# 方式一:
# 传统传参
def index(username):
    print(username)
    
def my_max(a, b):
    if a > b:
        return a
    return b

以下是用一个案例写出闭包函数的推导流程

# 方式二:
# 使用闭包函数实现比较两个数的大小

# 写闭包函数的推导流程
# 1.
def func():
    def my_max(a, b):
        if a > b:
            return a
        return b
    return my_max
res = func()  # my_max的内存地址
ret = res(2, 3)  # =>my_max()
print(ret)
# 这种不是闭包函数,功能可以实现,但是想要得到最后结果,还需要在内部函数my_max函数中,传入参数,比较麻烦

# 2.
def func():
    a = 1
    b = 10
    def my_max():
        if a > b:
            return a
        return b
    return my_max
res = func()  # my_max的内存地址
print(res())
# 这种是闭包函数,但此时func函数只能实现1和10的大小比较关系,所以要把a, b写活

# 3.
def func(a, b):
    def my_max():
        if a > b:
            return a
        return b
    return my_max
res = func(1, 10)  # my_max的内存地址
print(res())
# 这种是闭包函数,并且可以实现任何两个数大小的比较

2.3 实际应用

'''爬虫的知识'''
# 要先安装requests包
import requests

def func(url):
    # url = 'http://www.baidu.com'
    def get_content():
        # url = 'http://www.jd.com'
        # res=requests.get('http://www.baidu.com')
        res=requests.get(url)
        if res.status_code == 200:
            with open(r'aaa.html', 'wb') as f:
                f.write(res.content)
    
    return get_content

# res=func() # get_content
# res('http://www.jd.com')

res=func("http://www.jd.com")
res()
res()
res()  # 可以简单的多次调用

res1=func("http://www.baidu.com")
res1()
res1()
res1()

posted @ 2023-02-28 19:40  星空看海  阅读(13)  评论(0编辑  收藏  举报