第二模块第14章 函数对象和闭包

egon老师知乎:

https://zhuanlan.zhihu.com/p/109056932

内容概要:

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

2. 函数嵌套

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

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

一 函数对象

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

1. 可以赋值

2. 可以当作参数传给另外一个函数

3. 可以当作另外一个函数的返回值

4. 可以当成容器类型的一个元素

# 应用示例
def login():
    ...
def transfer():
    ...
def check():
    ...
def withdraw():
    ...
dic = {'1':login, '2':transfer, '3':check, '4':withdraw}
while True:
    print('''
    0 退出
    1 登录
    2 转账
    3 查询
    4 取款
    ''')
    choice = input('请输入命令编号:')
    if not choice.isdigit():
        print('输入有误, 请输入编号')
        continue
    if choice == '0':
        break
    if choice in dic:
        dic[choice]()
    else:
        print('输入的指令不存在, 请重新输入')
        continue
# 优化版
def login():
    print('登录')
def transfer():
    print('转账')
def check():
    print('查询')
def withdraw():
    print('取款')
dic = {
    '0':('退出', None),
    '1':('登录',login),
    '2':('转账',transfer),
    '3':('查询',check),
    '4':('取款',withdraw)}
while True:
    for k,v in dic.items():
        print(k,v[0])
    choice = input('请输入命令编号:')
    if not choice.isdigit():
        print('输入有误, 请输入编号')
        continue
    if choice == '0':
        break
    if choice in dic:
        dic[choice][1]()
    else:
        print('输入的指令不存在, 请重新输入')

二 函数嵌套

1. 函数的嵌套调用

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

# 示例:
def max2(x,y):
    if x > y:
        return x
    else:
        return y
def max4(a, b, c, d):
    res1 = max2(a, b)
    res2 = max2(res1, c)
    res3 = max2(res2, d)
    return res3
res = max4(2, 0, 8, 1)
print(res)
# 结果: 8

2. 函数的嵌套定义

  在函数内定义函数

  不是很常用, 最常用于闭包函数

def f1():
    def f2():
        pass
'''
如果f2供所有人使用, 应该放在全局, 如果只供f1用, 则应放在f1内.
'''

 三 闭包函数

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

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

2. 什么是闭包函数

'闭'函数指的是该函数是内嵌函数

'包'函数指的是该函数包含对外层函数作用域名字的引用(不是对全局作用域), 不管是对第几层函数作用域中名字的应用, 都叫包函数, 只要不是从自己所在的作用域找就行.

def f1():
    x = 11111
    def f2():
        print(x)
    return f2
f2 = f1()
f2()

3. 为何要有闭包函数, 闭包函数的应用

有了两种为函数传参的方式

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

def f(x):
    print(x)
f(1)

方式二: 闭包传参

import requests
# 传参的方案一
def get(url):
    response = requests.get(url)
    print(len(response.text))
get('https://www.baidu.com')

# 传参的方案二
def outer(url):
    # 传参相当于 url = 'https://www.baidu.com'
    def get():
        response = requests.get(url)
        print(len(response.text))
    return get
get = outer('https://www.baidu.com')
get()

 

egon老师知乎课件:

https://zhuanlan.zhihu.com/p/109056932

目录:

一 函数对象
1.1 函数可以被引用
1.2 函数可以作为容器类型的元素
1.3 函数可以作为参数传入另外一个函数
1.4 函数的返回值可以是一个函数
二 闭包函数
2.1 闭与包
2.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 

二 闭包函数

2.1 闭与包

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

x=1

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

    return f2

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

f3() #结果为1

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

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

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

import requests

#方式一:
def get(url):
    return requests.get(url).text

#方式二:
def page(url):
    def get():
        return requests.get(url).text
    return get

提示:requests模块是用来模拟浏览器向网站发送请求并将页面内容下载到本地,需要事先安装:pip3 install requests
对比两种方式,方式一在下载同一页面时需要重复传入url,而方式二只需要传一次值,就会得到一个包含指定url的闭包函数,以后调用该闭包函数无需再传url

# 方式一下载同一页面
get('https://www.python.org')
get('https://www.python.org')
get('https://www.python.org')
……

# 方式二下载同一页面
python=page('https://www.python.org')
python()
python()
python()
……

闭包函数的这种特性有时又称为惰性计算。使用将值包给函数的方式,在接下来的装饰器中也将大有用处

 

posted @ 2020-06-23 10:41  自由者妍  阅读(159)  评论(0)    收藏  举报