10--函数对象、嵌套和闭包函数

一、函数对象

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

# func=内存地址
def func():
    print('from func')
    
    
# 1、可以赋值 
f=func
print(f,func)  # 同一个内存地址
f()   # --》 func()


# 2、可以当做参数传给另外一个函数
def foo(x):  # x = func的内存地址
    print(x)  # func的内存地址
    x()   # func()

foo(func)  # foo(func的内存地址)


# 3、可以当做另外一个函数的返回值
def foo(x):  # x=func的内存地址
    return x  # return func的内存地址

res=foo(func)  # foo(func的内存地址)
print(res)  # res=func的内存地址

res()  # func()


# 4、可以当做容器类型的一个元素
l=[func,]
print(l)  # func的内存地址
l[0]()

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

二、函数嵌套

# 作用:隐藏代码在函数体内,外部无法看见这段代码


# 1、函数的嵌套调用:在调用一个函数的过程中又调用其他函数
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)

# 2、函数的嵌套定义:在函数内定义其他函数
def f1():
    def f2():
        pass

# 圆形
def circle(radius,action=0):
    from math import pi
    
    # 求圆形的求周长:2*pi*radius
    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)

三、闭包函数

1、大前提:

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

2、什么是闭包函数

"闭"函数指的该函数是内嵌函数(是定义在其他函数内的函数)
"包"函数指的该函数包含对外层函数作用域名字的引用(不是对全局作用域)

# 定义:
  若内嵌函数包含对外部函数作用域(而非全局作用域)中变量的引用,
  那么该’内嵌函数’就是闭包函数,简称闭包(Closures)
    
  # 因而无论在何处调用闭包函数,使用的仍然是包裹在其外层的变量。


# 下例中  f2 包含了 对 f1 的局部名称

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

x=11111
def bar():
    x=444444
    f1()  # 33333333333333333333

def foo():
    x=2222
    bar()  

foo()  # 33333333333333333333


# 闭包函数:函数对象
def f1():
    x = 33333333333333333333
    def f2():
        print('函数f2:',x)
    return f2

f=f1()    # f2
# print(f)

x=4444
f()  # 函数f2: 33333333333333333333

def foo():
    x=5555
    f()

foo() # 函数f2: 33333333333333333333

3、为何要有闭包函数

===》闭包函数的应用
# 两种为函数体传参的方式

# 方式一:直接把函数体需要的参数以参数(形参)的形式传入
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)  # f2的内存地址

x()  # 3


# 重点:
  若是一个函数无法直接给它传参,可考虑将其写成闭包函数,通过外部函数传参
import requests

# 传参的方案一:
def get(url):
    response=requests.get(url)
    print(len(response.text))

get('https://www.cnblogs.com/linhaifeng')
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


cnblogs=outter('https://www.cnblogs.com/linhaifeng')
cnblogs()
cnblogs()

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


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



# 注:闭包函数的这种特性有时又称为惰性计算。使用将值包给函数的方式,在接下来的装饰器中也将大有用处
posted @   Edmond辉仔  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示