python之闭包函数

python 之闭包函数

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

一、引入

大前提

  • 闭包函数是对名称空间与作用域, 函数对象, 函数嵌套的综合运用

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

  • 核心点:变量的查找关系是以函数定义阶段为准的

二、什么是闭包函数?闭 & 包

  • 闭函数:指的是定义在函数内部的函数

  • 包函数:闭函数引用了一个来自于外层函数的变量

    • 特点:访问的变量不是自己的,而是外层函数的

  • 以上函数,合到一起为闭包函数,即:闭包函数=闭函数+包函数

'总结一句话来说' : 定义在函数内部的函数, 并且该函数包含对外部函数作用域中名字的引用,该函数就称为闭包函数
    
代码一:
def f1():
    x = 10
    def f2():
        print(x)
​
# 这个f2就是闭包函数。
​
代码二:
def outter():
     name='egon'
     def inner():
         print('my name is %s' %name)
     return inner  #注意不能加括号,加了括号就是返回的不是inner这个函数,而是inner函数调用完之后返回的是一个值,inner函数默认没有值,会返回一个None。
​
f=outter()    #其实就是f=inner
print(f) #<function outter.<locals>.inner at 0x0000014E06AE3F70>
f() #my name is egon
  • 注意:作用域在函数定义阶段就规定死了,与调用的位置无关

    定义阶段已经规定死了到'outter'下面的"x"去拿
    def outter():
         x=2           
         def inner():
             # x=1
             print('from inner',x)
    ​
         return inner
    ​
    在全局里面定义也无效
     f=outter()  # f=inner
     print(f)
     x=11111111111111111
     f()  # 2
    ​
    把它装进一个函数,在函数里面再定义也是无效的
     def foo():
         x=111111111111111111
         f()
    ​
     foo()  # 2

     

三、为函数传值的方式

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

方式一: 将值以参数的形式传入

代码一:
def f2(x):
    print(x)
​
f2(1)
f2(2)
f2(3)
​
代码二:将以下"url"以参数的形式传入(也是最常用)
import requests #导入requests模块
​
def get(url):
    response=requests.get(url)下载
    if response.status_code == 200:
        print(response.text)
​
get('https://www.baidu.com')
get('https://www.python.org')
​
# 提示提示:requests模块是用来模拟浏览器向网站发送请求并将页面内容下载到本地,需要事先安装:pip3 install requests

方式二: 以包的形式传入(使用内嵌函数把函数包裹, 为被包裹的函数提供作用域名字的引用)

代码一:
def outter(x):
    def wrapper():
        print(x)    #按照查找的优先级去查找"x"
    return wrapper  #吐出了函数"wrapper"的内存地址
​
f = outter(10)  #这里返回的值就是函数"wrapper"的内存地址,赋值给"f",加括号就调用
f()  #10
​
代码二:
def f1(x):
    # x = 333
    def f2():
        print(x)
    return f2
​
f = f1(333)  # 把原本属于f1局部的函数的名字, 拿到了全局.
print(f)  # <function f1.<locals>.f2 at 0x000001DBF8C3CE50>
​
f()  # 333, 实现了多次调用同一种传参的功能, 不需要重复传参.
f()  # 333
f()  # 333
​
代码三:这是个获取网络源码的功能
import requests    
​
def outter(url):
    def get():
        response=requests.get(url)
        if response.status_code == 200:
            print(response.text)
    return get
    
baidu = outter('https://www.baidu.com')
baidu()

对比两种方式,方式一在下载同一页面时需要重复传入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()
……

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

四、闭包的作用:

被引用的非全局变量也称作自由变量,这个自由变量会与内层函数产生一个绑定关系。 自由变量不会在内存中消失。

1、保证数据安全。函数外无法访问自由变量。

def func1():
    li = []
    def func2(x):
        li.append(x)
        return li
    ruturn func2
f = func1()
print(f(100))   # [100]
print(f(100))   # [100, 100]
print(f(100))   # [100, 100, 100]
#li就是自由变量,并没有消失,但无法从函数外访问。

2、为内部函数传参。

返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。

def f1(x):
    def f2():
        print(x,y)  # 优先使用外层的作用域,不会被全局所影响。
    x = 10
    y = 20
    return f2
​
x = 1
y = 2
f1(x)()
10 20

五、如何判断一个嵌套函数是不是闭包:

print(func.__code__.co_freevars)
# 只要返回值有自由变量那么就是闭包
​
def func():
    x = 10
    def f1():
        print(x)
    return f1
​
print(func().__code__.co_freevars)
('x',)
	
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贾维斯Echo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值