zoukankan      html  css  js  c++  java
  • 闭包和迭代器

     

    一.函数名的运用

      函数名是一个变量, 但它是一个特殊的变量, 与括号配合可以执行函数的变量.

    1. 函数名的内存地址

    2. 函数名可以赋值给其他变量

     

    3. 函数名可以当做容器类的元素 

     

     4. 函数名可以当做函数的参数

    5. 函数名可以作为函数的返回值

     

    def panpan():
        print("我是潘潘. 我喜欢毒丈夫 ")
    
    def xiaoping():
        print("我是小萍萍. 我喜欢毒丈夫 ")
    
    def xiaohua():
        print("我是小花花. 我喜欢毒丈夫 ")
    
    def daguanren():
        print("大官人喜欢xxxx")
    
    def wangpo(nv, nan): # 核心业务逻辑
        nv()
        nan()
    
    wangpo(xiaohua, daguanren) # 王婆代理了大官人和潘潘
    def play(wanjv1, wanjv2, wanjv3):
        '''
            玩儿函数
            :param wanjv1: 玩具1
            :param wanjv2: 玩具2
            :param wanjv3: 玩具3
            :return: 开心
        '''
        print("我要玩儿荡秋千")
        return "开心"
    
    
    # play("独木桥", "独轮车", "独眼龙")
    print(play.__doc__) #  document
    print(str.join.__doc__)

     二. 闭包

    def func():
        a = 10
        print(a)
    func()
    print(a) # 在外面你是访问不到局部变量的, 局部变量是安全的
    
    
    # 全局变量可能会被修改, 全局变量是不安全的. 可能会被其他函数所更改
    a = 10
    def func():
        global a
        a = 20
        print(a)
    func()
    print(a)
    
    # 用闭包可以保护我们的变量
    # 写法: 在外层函数中声明一个变量. 在内层函数使用或者返回这个变量.
    # 这个结构叫闭包
    # 1.可以保护我的变量
    # 2.可以让一个变量常驻内存

    什么是闭包? 闭包就是内层函数, 对外层函数(非全局)的变量的引用. 叫闭包

     

    我们可以使用__closure__来检测函数是否是闭包. 使用函数名.__closure__返回cell就是
    闭包. 返回None就不是闭包

     

    问题, 如何在函数外边调用内部函数呢?

     那如果多层嵌套呢? 很简单, 只需要一层一层的往外层返回就行了

     

    由它我们可以引出闭包的好处. 由于我们在外界可以访问内部函数. 那这个时候内部函
    数访问的时间和时机就不一定了, 因为在外部, 我可以选择在任意的时间去访问内部函数.
    个时候. 想一想. 我们之前说过, 如果这个函数执行完毕. 则这个函数中的变量以及局部命名
    空间中的内容都将会被销毁. 在闭包中. 如果变量被销毁了. 那内部函数将不能正常执行.
    . python规定. 如果你在内部函数中访问了外层函数中的变量. 那么这个变量将不会消亡.
    将会常驻在内存中. 也就是说. 使⽤闭包, 可以保证外层函数中的变量在内存中常驻. 这样做
    有什么好处呢? 非常大的好处. 我们来看这个关于爬虫的代码 :

    from urllib.request import urlopen
    
    def func():
        # 闭包. content会常驻内存
        content = urlopen("http://www.xiaohuar.com/").read()
        def inner():
            return content
        return inner
    
    print("加载中...")
    g = func() # 网络请求
    print("加载完毕")
    print(g())
    print(g())
    print(g())

    . 迭代器

     我们之前一直在用可迭代对象进行迭代操作. 那么到底什么是可迭代对象. 这个主要讨
    论可迭代对象. ⾸先我们先回顾一下之前我们所熟知的可迭代对象有哪些:
    str, list, tuple, dict, set. 那为什么我们可以称他们为可迭代对象呢? 因为他们都遵循了可
    迭代协议. 什么是可迭代协议. 首先我们先看一段错误代码:

    注意看报错信息中有这样一句话. 'int' object is not iterable . 翻译过来就是整数类型对象
    是不可迭代的. iterable表⽰可迭代的. 表示可迭代协议. 那么如何进行验证你的数据类型是否
    符合可迭代协议. 我们可以通过dir函数来查看类中定义好的所有方法 

    在打印结果中. 寻找__iter__ 如果能找到. 那么这个类的对象就是一个可迭代对象

     

    我们发现在字符串中可以找到__iter__. 继续看一下list, tuple, dict, set

    ['__add__', '__class__', '__contains__', '__delattr__', '__dir__',
    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
    '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__',
    '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__',
    '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__',
    '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count',
    'index']
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
    '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
    '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__',
    '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__',
    '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
    '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__',
    '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count',
    'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    ['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', '__dict__',
    '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__',
    '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__',
    '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__ne__',
    '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__',
    '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_checkClosed',
    '_checkReadable', '_checkSeekable', '_checkWritable', '_finalizing',
    'buffer', 'close', 'closed', 'detach', 'encoding', 'errors', 'fileno',
    'flush', 'isatty', 'line_buffering', 'mode', 'name', 'newlines', 'read',
    'readable', 'readline', 'readlines', 'seek', 'seekable', 'tell',
    'truncate', 'writable', 'write', 'writelines']
    ['__and__', '__class__', '__contains__', '__delattr__', '__dir__',
    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',
    '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__',
    '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__',
    '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__',
    '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__','__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear',
    'copy', 'difference', 'difference_update', 'discard', 'intersection',
    'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop',
    'remove', 'symmetric_difference', 'symmetric_difference_update', 'union',
    'update']
    ['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__',
    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
    '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__',
    '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__',
    '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__',
    '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys',
    'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
    list, tuple, dict, set

    我们发现这一个可以进行for循环的东西都有__iter__函数, 包括range也有. 可以试一试
    .
    这是查看这个对象是否是可迭代对象的第一种办法. 我们还可以通过isinstence()函数来查
    看这个对象是什么类型的

    l = [1,2,3]
    l_iter = l.__iter__()
    from collections import Iterable
    from collections import Iterator
    print(isinstance(l,Iterable)) #True
    print(isinstance(l,Iterator)) #False
    print(isinstance(l_iter,Iterator)) #True
    print(isinstance(l_iter,Iterable)) #True
    isinstance

    综上. 我们可以确定. 如果对象中有__iter__函数. 那么我们认为这个对象遵守了可迭代协议.
    就可以获取到相应的迭代器. 这个的__iter__是帮助我们获取到对象的迭代器. 我们使用迭代
    器中的__next__()来获取到⼀个迭代器中的元素. 那么我们之前讲的for的工作原理到底是什
    ? 继续看代码

    lst = [1,2,3]
    it = lst.__iter__()
    print(it.__next__())
    print(it.__next__())
    print(it.__next__())
    
    # 重新拿一个迭代器
    it = lst.__iter__()
    print(it.__next__())
    print(it.__next__())
    print(it.__next__())
    原理

    for循环的机制

    for i in [1,2,3]:
    print(i)

     使用while循环+迭代器来模拟for循环(必须要掌握)

    lst = [1,2,3]
    lst_iter = lst.__iter__()
    while True:
    try:
    i = lst_iter.__next__()
    print(i)
    except StopIteration:
    break
    #  总结
    # 特点:
    # 1. 节省内存
    # 2. 惰性机制
    # 3. 只能向前. 不能反复
    # 小总结
    # Iterable: 可迭代对象. 里面包含了__iter__(),可以使用for循环
    # Iterator: 迭代器. 里面包含了__iter__() 和 __next__(), 也可以使用for循环

    # from collections import Iterable # 可迭代的
    # from collections import Iterator # 迭代器
  • 相关阅读:
    http基本概念和常见状态码
    JDK1.7 hashMap并发扩容死循环原理
    HashMap初始化数组原理,为什么是2的N次方?
    Rest接口加Http单向认证
    post和get乱码解决方法
    用迭代法实现二叉树的前、中、后序遍历
    搭建基于Zookeeper和solr的分布式搜索:solrcloud
    正向代理,反向代理及其作用
    二分查找向左或向右紧缩
    tcp四次挥手
  • 原文地址:https://www.cnblogs.com/zhaodingding/p/9670929.html
Copyright © 2011-2022 走看看