• python之函数闭包、可迭代对象和迭代器


    一、函数名的应用

    复制代码
    # 1,函数名就是函数的内存地址,而函数名()则是运行这个函数。
    def func():
        return
    
    print(func)  # 返回一个地址
    
    # 2,函数名可以作为变量。
    def func1():
        print(666)
    
    f1 = func1
    f2 = f1
    f2()  # 就等于func1() 此时执行函数
    
    # 3,函数名可以作为函数的参数。
    def func1():
        print(666)
    
    def func2(x):
        x()
    
    func2(func1)  # 输出666 func1作为实参传进func2中,此时在func2中x()等于func1()
    
    # 4,函数名可以当做函数的返回值。
    def wraaper():
        def inner():
            print(666)
        return inner
    
    ret = wraaper()  # 执行函数wraaper(),得到返回值inner赋值给ret,这个inner是函数名
    ret()  # 输出666,ret()等于inner()
    # (注意:这里要调用inner()只能是用ret(),因为inner()是wraaper()的嵌套函数,在全局命名空间中并没有声明,所以直接用inner()不能执行,)
    
    def func2():
        print('in func2')
    
    def func3(x):
        print('in func3')
        return x
    
    f = func3(func2)  # 给func3传进一个参数func2,返回func2赋值给f
    f()  # f()等于func2()
    
    # 5,函数名可以作为容器类类型的元素。
    def f1():
        print('f1')
    
    def f2():
        print('f2')
    
    def f3():
        print('f3')
    
    l = [f1, f2, f3]
    d = {'f1': f1, 'f2': f2, 'f3': f3}
    # 调用
    l[0]()  # 输出 f1
    d['f2']()  # 输出 f2
    
    
    def func1():
        print('in func1')
    
    def func2():
        print('in func2')
    
    def func3():
        print('in func3')
    
    def func4():
        print('in func4')
    
    l1 = [func1,func2,func3,func4]
    
    #调用
    for i in l1:
        i()
    
    # 像上面的函数名这种,称为第一类对象。
    # 第一类对象(first-class object)指:
    # 1.可在运行期创建
    # 2.可用作函数参数或返回值
    # 3.可存入变量的实体。
    # (如果不明白,那就记住一句话,就当普通变量用)
    复制代码

    6、globals()        locals()
    globals()    #返回全局变量(包含内置函数)的一个字典。
    locals()      #返回当前位置的变量的字典。
    例如:

    复制代码
    def func1():
        a = 2
        b = 3
        print(globals())  # 此时globals()在局部命名空间中,但也是返回全局命名空间的一个字典
        print(locals())  # 此时locals()在局部命名空间中,所以返回的是局部命名空间的一个字典{'b': 3, 'a': 2}
    
    print(globals())  # 此时globals()在全局命名空间中,返回全局命名空间的一个字典
    print(locals())  # 此时locals()在全局命名空间中,所以返回的是全局命名空间的一个字典
    func1()
    
    # 结果:
    
    # {'__name__': '__main__', '__doc__': None(后面还有一大推东西,省略)...}
    
    # {'__name__': '__main__', '__doc__': None(后面还有一大推东西,省略)...}
    
    # {'__name__': '__main__', '__doc__': None(后面还有一大推东西,省略)...}
    
    # {'b': 3, 'a': 2}
    复制代码

    总结:
    globals()无论在哪个命名空间,返回的都是全局命名空间的一个字典
    locals()在哪个命名空间就返回哪个命名空间的字典

    复制代码
    def func1():
        a = 2
        b = 3
        def inner():
            c = 5
            d = 6
            print(globals())    #{'__name__': '__main__', '__doc__': None(后面还有一大推东西,省略)...}
            print(locals())      #{'c': 5, 'd': 6}
        inner()
    func1()
    复制代码

     


    二、闭包
    1、内层函数引用外层函数的变量(非全局变量),这样该内部函数称就称为闭包函数。
    (我们都知道函数内的变量我们要想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?
    就把这个函数的名字返回就好了,这是闭包函数最常用的用法)

    复制代码
    def wraaper():
        name = '鬼见愁'
        def inner():
            print(name)
        return inner
    
    f = wraaper()
    f()
    复制代码

    2、判断闭包函数的方法__closure__

    复制代码
    # 1,是闭包返回值会有cell元素
    def wraaper():
        name = '鬼见愁'
        def inner():
            print(name)
        print(inner.__closure__)
        return inner
    f = wraaper()
    f()
    
    
    # 2,不是闭包就会返回None
    name = '鬼见愁'
    def wraaper():
        def inner():
            print(name)
        print(inner.__closure__)  # None
        return inner
    f = wraaper()
    f()
    
    
    name = '番薯'
    def wraaper(n):
        n = '番薯'
        def inner():
            print(n)
        print(inner.__closure__)  # cell at 0x000002AD93BF76D8
        inner()
        return inner
    wraaper(name)
    复制代码

    '''
    闭包作用:
      当程序执行时,遇到了函数执行,他会在内存中开辟一个空间,局部名称空间,
      如果这个函数内部形成了闭包,
      那么它就不会随着函数的结束而消失。
    '''


    什么时候用到闭包?
    例如:爬虫,装饰器等
    下面是一个爬虫的小案例:

    复制代码
    from urllib.request import urlopen
    def index():
        url = "http://www.xiaohua100.cn/index.html"
        def get():
            return urlopen(url).read()
        return get
    
    xiaohua = index()  # get
    content = xiaohua()  # get()
    print(content.decode('utf-8'))
    复制代码


    三、可迭代对象
    for i in 'abc':
      print(i)

    for i in 123:
      print(i)     # 'int' object is not iterable表示不是可迭代对象

    对象内部含有__iter__方法就是可迭代对象.
    可迭代对象满足可迭代协议。

    可迭代对象:str list dict,tuple,set,range()
    dir() :返回一个列表,列表里面包含了传入的参数的属性、方法

    s1 = 'strs'

    print(dir(s1))

    判断一个对象是否是可迭代对象:

    复制代码
    # 第一个方法
    s1 = 'abc'
    dic = {'name':'xiaoming'}
    print('__iter__' in dir(s1))
    print('__iter__' in dir(dic))
    
    
    # 第二种方法
    from collections import Iterable  #判断是否为可迭代对象
    from collections import Iterator  #判断是否为迭代器
    
    print(isinstance('xiaoming',Iterable))  # True
    print(isinstance('xiaoming',Iterator))  # False
    
    print(isinstance('xiaoming',str)) # True
    #isinstance() 应用比type()更广泛,isinstance()不仅可以判断你是不是可迭代对象,
    #也可判断你是否迭代器,还可以判断你是什么类型的数据等等,而#type()只能判断你是什么数据类型
    复制代码

    四、迭代器
    1、对象内部含有__iter__方法且含有__next__方法就是迭代器。

    复制代码
    #文件句柄是迭代器:
    f = open('register', encoding='utf-8')
    print('__iter__' in dir(f))      #True
    print('__next__' in dir(f))      #True
    
    #字典是可迭代对象,不是迭代器。
    print('__iter__' in dir(dict))   #True
    print('__next__' in dir(dict))   #False
    复制代码


    2、可迭代对象与迭代器的区别:
    1,可迭代对象不能取值,迭代器是可以取值的。
    (我们知道字典列表都是可迭代对象,为什么它们能取值呢?这是因为为了方便我们操作,我们设定了
    索引(键)用来操作字典列表取值,如果没有人为为它们设置的索引(键),它们是不能取值的)
    2, 迭代器非常节省内存。
    3,迭代器每次只会取一个值。
    4,迭代器单向的,一条路走到头。


    3、可迭代对象 --->(转化成)迭代器

    lis = [1, 2, 3]  # 可迭代对象
    ite1 = lis.__iter__()  # 迭代器  <list_iterator object at 0x0000027A183BFFD0>
    ite1 = iter(lis)  # 迭代器  <list_iterator object at 0x0000027A183BFFD0>
    print(ite1)

    4、迭代器如何取值? next一次,取一个值

    print(ite1.__next__())
    print(ite1.__next__())
    print(ite1.__next__())

    5、while循环模拟for循环机制
    1,将可迭代对象转化成迭代器。
    2,调用__next__方法取值。
    3,利用异常处理停止报错。

    复制代码
    s1 = 'abcdefg'
    iter1 = s1.__iter__()
    while 1:
        try:
            print(iter1.__next__())
        except StopIteration:
            break
    复制代码
  • 相关阅读:
    Go 命令行参数,JSON 序列化与反序列化
    Go 文件操作
    Go 多态
    Go 接口
    Go 面向对象三大特性
    Go 面向对象编程应用
    Go 结构体方法
    Go 面向对象之结构体
    Go Map
    vue安装 vue-cli安装
  • 原文地址:https://www.cnblogs.com/yidashi110/p/10092280.html
Copyright © 2020-2023  润新知