zoukankan      html  css  js  c++  java
  • 铁乐学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

  • 相关阅读:
    POJ 2240 Arbitrage spfa 判正环
    POJ 3259 Wormholes spfa 判负环
    POJ1680 Currency Exchange SPFA判正环
    HDU5649 DZY Loves Sorting 线段树
    HDU 5648 DZY Loves Math 暴力打表
    HDU5647 DZY Loves Connecting 树形DP
    CDOJ 1071 秋实大哥下棋 线段树
    HDU5046 Airport dancing links 重复覆盖+二分
    HDU 3335 Divisibility dancing links 重复覆盖
    FZU1686 神龙的难题 dancing links 重复覆盖
  • 原文地址:https://www.cnblogs.com/tielemao/p/8711469.html
Copyright © 2011-2022 走看看