美文网首页
py_16 函数对象和闭包函数

py_16 函数对象和闭包函数

作者: 阿登20 | 来源:发表于2020-08-12 21:42 被阅读0次
一 函数对象
    1.1 赋值给变量
    1.2 函数可以作为容器类型的元素
    1.3 函数可以作为参数传入另外一个函数
    1.4 函数的返回值可以是一个函数
    **案例** **利用该特性,优雅的取代多分支的if**
二 闭包函数
    2.1 闭与包 :无论在哪里调 都是在函数定义阶段,找作用域关系
     闭 函数指的是内层函数是定义在一个函数内的函数
     包 函数指的是内层函数包含对外层函数作用域名字的引用(不是对全局作用域)
    2.2 两种为函数体传参的两种方式:1.直接传参  2. 闭包

一 函数对象

函数对象指的是函数可以被当做’数据’来处理,具体可以分为四个方面的使用,我们如下

1.1 赋值给变量

>>> def add(x,y):
...     return x+y
... 
>>> func=add
>>> func(1,2)
3

1.2 函数可以作为容器类型的元素

>>> dic={'add':add,'max':max}
>>> dic
{'add': <function add at 0x100661e18>, 'max': <built-in function max>}
>>> dic['add'](1,2)
3

1.3 函数可以作为参数传入另外一个函数

>>> def foo(x,y,func):
...     return func(x,y)
...
>>> foo(1,2,add)
3

1.4 函数的返回值可以是一个函数

def bar(): 
     return add 
func=bar() 
func(1,2)
3 

案例 利用该特性,优雅的取代多分支的if

# 应用场景

def login():
    print("登录成功")

def transfer():
    print("转账成功")

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

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


while True:
    print("""
    0 退出
    1 登录
    2 转账
    3 查询余额
    """)
    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()
    else:
        print("输入的指令不存在")

# 痛点
# 假如以后我要增加10个功能,那么我还得写10个elif。程序员不能这么干。
# 如果我们把函数名也就是函数内存地址,存在一个容器里面,是否可以实现呢?比如字典 列表
# 字典可以通过key去取函数内存地址,列表可以for循环 forkey,func in enumerate(list)
# 怎么解决: 把函数名作为一个字典的值
def login():
    print("登录成功")

def transfer():
    print("转账成功")

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

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

def recharge():
    print("充值")
# 之后 新增的功能只要加到字典里就行,判断输入key在不在func_dict里面,在就通过key取出来加括号调用
func_dict={
    "1":login,
    "2":transfer,
    "3":check_banlance,
    "4":withdraw,
    "5":recharge
}

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_dict:
        func_dict[choice]()
    else:
        print("输入的指令不存在")

继续优化提示信息

# 继续优化 提示信息

def login():
    print("登录成功")

def transfer():
    print("转账成功")

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

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

def recharge():
    print("充值")
# 字典的value用元组存函数名 和提示信息
func_dict={
    "0":("退出",None),
    "1":("登录",login),
    "2":("转账",transfer),
    "3":("查询余额",check_banlance),
    "4":("提现",withdraw),
    "5":("充值",recharge)
         }

while True:
    # 前面提示信息这里用for循环打印
    for k,msg in func_dict.items():
        print(k,msg[0])
    choice = input("请输入编号-->:").strip()
    if not choice.isdigit():
        print("请输入编号")
        continue
    if choice == "0":
        break
    if choice in func_dict:
        func_dict[choice][1]()
    else:
        print("输入的指令不存在")

二 闭包函数

2.1 闭与包

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

def f1():  # f1相当于麻袋
    x = 1
    def f2(): # f2闭函数,要去引用外层作用域才是包函数
        print("函数f2:",x)
    return f2
f = f1() # 拿到f,无论在哪里调都是用它外层的x.一个局部的f2可以在全局f去调用f2函数
x = 6666
f() # 无论在哪里调 都是在函数定义阶段,找作用域关系。 # 1

def foo():
    x = 555 # 下面一行代码调用,不会取555,而是在函数定义处去找。x=1
    f()
# 什么是闭包函数
# 闭 函数指的是内层函数[f2]是定义在[f1]一个函数内的函数
# 包 函数指的是内层函数[f2]包含对外层函数[f1]作用域名字的引用(不是对全局作用域)

基于函数对象的概念,可以将函数返回到任意位置去调用,但作用域的关系是在定义完函数时就已经被确定了的,与函数的调用位置无关。

x=1

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

    return f2

def f3():
    x=3
    f2=f1() #调用f1()返回函数f2
    f2() #需要按照函数定义时的作用关系去执行,与调用位置无关

f3() #结果为1

2.2 两种为函数体传参的两种方式

# 方式一 : 直接把函数体需要的参数定义成形参
def my(x):
    print(x)
my(2)
my(3)

# 方式二:
def f1():
    x = 3
    def my():
        print(x)
    return my
m = f1() # 重新拿到 f1下my的内存地址,等于是my的内存地址指向m,m就是my
m()

def f1(x):
    # x = 3 这里注释,那么可以给函数f1可以传一个参数 x
    def my():
        print(x)
    return my
m = f1(3) # 重新拿到 f1下my的内存地址,等于是my的内存地址指向m,m就是my
m()
print(m.__closure__)
# (<cell at 0x00000000028C2588: int object at 0x000007FECF90E390>,)
print(m.__closure__[0].cell_contents) # 3

也就是说函数被当做数据处理时,始终以自带的作用域为准。若内嵌函数包含对外部函数作用域(而非全局作用域)中变量的引用,那么该’内嵌函数’就是闭包函数,简称闭包(Closures)

x=1
def outer():
    x=2
    def inner():
        print(x)
    return inner

func=outer()
func() # 结果为2

可以通过函数的closure属性,查看到闭包函数所包裹的外部变量

>>> func.__closure__
(<cell at 0x10212af78: int object at 0x10028cca0>,)
>>> func.__closure__[0].cell_contents
2

“闭”代表函数是内部的,“包”代表函数外’包裹’着对外层作用域的引用。因而无论在何处调用闭包函数,使用的仍然是包裹在其外层的变量。

总结: 闭包其实就是多一种为函数传参的方式,下面给个案例

import requests

# 方式一: 直接传参
def get(url):
    res = requests.get(url)
    print(len(res.text))
# 方式2:闭包
def outter(url):
    # url= "https://www.baidu.com"
    def get():  # 闭包这里可以看成把 4--6的代码,用outter包起来。url作用域外层的传参
        res = requests.get(url)
        print(len(res.text))
    return get  #
# 
g = outter("https://www.jianshu.com/u/d653f5c19c1b")
g()

对比两种方式,方式一需要重复传入url,而方式二只需要传一次值,就会得到一个包含指定url的闭包函数,以后调用该闭包函数无需再传url

相关文章

  • py_16 函数对象和闭包函数

    一 函数对象 函数对象指的是函数可以被当做’数据’来处理,具体可以分为四个方面的使用,我们如下 1.1 赋值给变量...

  • 函数对象和闭包

    函数对象和闭包 一) 函数对象 示例: 二)函数嵌套 三)闭包函数

  • day14-函数(3)装饰器

    一、闭包函数 闭包函数=函数嵌套定义+函数对象+名称空间与作用域 闭包函数 1、闭:指的是该函数是定义在一个函数内...

  • day14 装饰器

    Ⅰ 闭包函数 闭包函数=函数嵌套定义+函数对象+名称空间作用域 闭:指的是该函数是定义再一个函数内部的函数...

  • python之理解闭包和装饰器

    python之理解闭包和装饰器 1、闭包函数 1.1 python中函数都是对象 结果: 上面定义一个shut函数...

  • 内存泄漏

    闭包 在闭包中,内部函数引用外部函数变量,实际上是应用了外部函数的作用域(scope)对象 如果作用域对象所在函数...

  • 06-mini-web框架02

    闭包 多层函数的嵌套 内部函数用到外部函数的变量 函数、匿名函数、闭包、对象当做实参的区别 匿名函数嫩能够完成基本...

  • JS高级学习:函数

    案例 函数作为返回值 案例2: 闭包 闭包的优缺点:缓存数据 函数模式的闭包:在一个函数中有一个函数 对象模式的闭...

  • 面试题(day-2)

    1 ,什么是闭包?闭包有什么好处?使用闭包要注意什么? 闭包:函数嵌套函数,内部函数可以引用外部函数的参数和变量,...

  • 闭包函数

    闭包函数 闭包,又称闭包函数或者闭合函数,其实和嵌套函数类似,不同之处在于,闭包中外部函数返回的不是一个具体的值,...

网友评论

      本文标题:py_16 函数对象和闭包函数

      本文链接:https://www.haomeiwen.com/subject/uwxvdktx.html