• 铁乐学Python_day11_闭包函数


    一、【函数名】

    1)函数名本质上它也是一种变量,特殊的变量;
    (碰到同名其它变量,依照从上往下的代码执行赋值。)
    单独打印函数名,输出的是它对应的内存地址:
    
    例:
    def funcl():
        print(666)
    print(funcl)
    
    返回如下:
    <function funcl at 0x0000000000DF5488>
    
    2)函数名可以赋值给其它变量名;
    def funcl():
        print(666)
    
    f1 = funcl
    f1()
    
    666
    
    3)函数名可以作为容器类的元素;
    def funcl():
        print(666)
    # print(funcl)
    
    f1 = funcl
    f1()
    
    def f2():
        print(222)
    
    def f3():
        print(333)
    
    def f4():
        print(444)
    
    li =[f1, f2, f3, f4]
    print(li)
    
    # 返回的是对应的内存地址
    
    for i in li:
        i()
    
    # 依次执行函数,可以看到函数名作为列表(容器)的元素也是可以的。
    666
    222
    333
    444
    
    4)函数名可以作为参数;
    def f1():
        print(666)
    
    def f2(a):
        a()
        print(777)
        
    f2(f1)                                                                                          
    
    输出的结果:
    666
    777
    
    上例中f1函数名是作为f2函数的参数。
    
    5)函数名可以作为函数的返回值。
    例:
    def f1():
        print(666)
    
    def f2():
        return f1
    
    f2()()
    
    # 输出666
    
    def f3():
        def f4():
            print(777)
        return f4
    
    f3()()
    
    #输出 777
    

    以上例子可以看出函数名也可以作为函数的返回值,而且通过return返回的嵌套函数可以调用执行成功。
    像上例中的f3()()如果改成f4()是会报错:NameError: name 'f4' is not defined,原因就是全局命名空间中找不到f4()函数定义。所以这是命名空间很神奇的一个地方。

    二、【闭包函数】

    内层函数对外层函数,非全局变量的引用。
    判断闭包函数:函数名.closure(),返回的值中有cell这个元素表示该函数为闭包函数。
    闭包函数的机制:当函数开始执行时,如果遇到了闭包,在内存当中会为闭包开辟一个内存空间,用于将闭包中的变量等值放入其中,并不会随着函数的执行完毕而消失。

    函数内部定义的函数称为内部函数

    主要作用有:
    1)缓存,节省内存空间;例如爬虫用,(不断重复爬取同一网页的情况下)
    2)装饰器,最能完整体现出闭包的作用。

    由于作用域的关系,
    我们不能直接拿到函数内部的变量和函数了。如果我们就是想拿怎么办呢?通过返回值!
    函数内的变量要想在函数外部用,可以直接返回这个变量,那么如果想在函数外部调用函数内部的函数呢?
    是不是直接就把这个函数的名字返回就好了?
    这才是闭包函数最常用的用法。所以这也是装饰器之所以是闭包函数最能完整体现用法的原因。

    例:闭包函数的运用,引用外层的函数。
    def func():
        name = 'eva'
        def inner():
            print(name)
        return inner
    
    func() # 直接执行func,并没有调用到func里面的inner函数,不会输出eva
    f = func()
    f() # 相当于是执行func()(),而func()中返回了inner函数,
        # 所以又相当于是在func函数体内部中执行func(inner),所以就能正常执行了。
    
    #输出
    
    eva
    
    例:判断是否为闭包函数
    函数名.__closure__()
    #输出的__closure__有cell元素 :是闭包函数
    def func():
        name = 'eva'
        def inner():
            print(name)
        print(inner.__closure__)
        return inner
    
    f = func()
    f()
    
    print('我是华丽的分割线'.center(30, '-'))
    
    #输出的__closure__为None :不是闭包函数(没有引用外层,试图引用的是全局的变量,所以不为闭包)
    name = 'egon'
    def func2():
        def inner():
            print(name)
        print(inner.__closure__)
        return inner
    
    f2 = func2()
    f2()
    
    (<cell at 0x0000000000BF9138: str object at 0x0000000000BE0D18>,)
    eva
    -----------我是华丽的分割线-----------
    None
    egon
    
    例:闭包的嵌套(两层,还可以嵌套到三层,一般三层己够满足需要了)
    下面是借助不断给函数名赋值成变量来调用嵌套的函数的,这个方法其实在说到装饰器时会用上,为什么要简化成一个变量名()的方式,就是为了装饰其他函数用(不用改变其他函数的表现形式)
    def wrapper():
        money = 1000
        def func():
            name = 'eva'
            def inner():
                print(name, money)
            return inner
        return func
    
    f = wrapper()
    i = f()
    i()
    
    eva 1000
    
    例:闭包函数获取网络应用(简单爬虫雏形)
    下例为我爬取我的个人wordpress博客首页所用的简单代码,
    到最后的内容需要用到decode解码才能看到页面源代码。
    还可以更进一步使用文件操作写入到文件。
    from urllib.request import urlopen
    
    def index():
        url = "https://www.tielemao.com"
        def get():
            return urlopen(url).read()
        return get
    
    tielemao = index()
    content = tielemao()
    print(content.decode('utf-8'))
    
    写到文件上保存:
    from urllib.request import urlopen
    
    def index():
        url = "https://www.tielemao.com"
        def get():
            return urlopen(url).read()
        return get
    
    tielemao = index()
    content = tielemao()
    # print(content.decode('utf-8'))
    s = content.decode('utf-8')
    with open('tielemao_index.html', encoding='utf-8', mode='a') as f1:
        f1.write(s)
    

    end
    2018-4-3

  • 相关阅读:
    Orcle数据库查询练习复习:二
    Orcle数据库查询练习复习:一
    Xamarin.Android 入门之:xamarin使用webserver和html交互
    Xamarin.Android 入门之:Listview和adapter
    Xamarin.Android 入门之:Android的生命周期
    Xamarin.Android 入门之:Android API版本设置
    Xamarin.Android 入门之:Xamarin快速入门
    阶段01Java基础day16集合框架02
    阶段01Java基础day13常见对象02
    阶段01Java基础day10面向对象05
  • 原文地址:https://www.cnblogs.com/tielemao/p/8711469.html
Copyright © 2020-2023  润新知