zoukankan      html  css  js  c++  java
  • 函数的三大器

    迭代器

      1.函数名的使用以及第一类对象

      2.闭包

      3.迭代器

    一.函数名的运用

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

      1.函数名的内存地址

    def func():
        print('呵呵')
    print(func)

    # 结果:
    # <function func at 0x0000000000502E18>

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

        

    def func():
        print('呵呵')
    
    
    a = func
    a()
    
    # 结果:
    #  呵呵

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

    def func1():
        print('呵呵111')
    def func2():
        print('呵呵222')
    def func3():
        print('呵呵333')
    def func4():
        print('呵呵444')
    
    
    li = [func1,func2,func3,func4]
    for func in li:
        func()
        
    # 结果:
    '''
    呵呵111
    呵呵222
    呵呵333
    呵呵444
    '''

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

      

    def func():
        print('你是谁?我是猪八戒啊')
    
    def fn(s):
        print('谁在我里面,谁在说话?')
        s()
        print('哇,不好了,连我也中招了')
    
    fn(func)
    
    #  结果
    '''
    谁在我里面,谁在说话?
    你是谁?我是猪八戒啊
    哇,不好了,连我也中招了
    '''

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

      

    def func():
        print('我是func ')
        def fn():
            print('我是fn')
        print('我是func')
        return fn
    
    fn = func()
    fn()
    
    # 结果
    '''
    我是func 
    我是func
    我是fn
    
    '''

     二 .闭包

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

      

    def fuc():
        name = 'hahage'
        def foo():
            print(name)
        foo()
    fuc()
    # 结果:
    # hahage

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

      

    def func():
        name = '哈哈哥'
        def foo():
            print(name)
        foo()
        print(foo.__closure__)
    func()
    
    # 结果:
    # 哈哈哥
    # (<cell at 0x00000000026F7D98: str object at 0x00000000021EAA50>,)

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

    def outer():
        name = '哈哈哥'
        def foo():
            print(name)
        return foo
    foo = outer()  # 访问外部函数,获取到内部函数的函数地址
    foo()          # 访问内部函数
    
    # 结果
    # 哈哈哥

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

    def func():
        def foo():
            def fn():
                print('嘿嘿嘿')
            return fn
        return foo
    foo = func()
    fn = foo()
    fn()
    # 结果
    # 嘿嘿嘿

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

    from urllib.request import urlopen
    def but():
        content = urlopen('http://www.521609.com/').read()
        def get_content():
            return content
        return get_content
    fn = but()
    content = fn()
    print(content)
    
    content2 = fn()
    print(content2)

      综上; 闭包的作用就是让一个变量能够常驻内存,供后面的程序使用

      三 . 迭代器

        我们之前一直在用可迭代对象进行迭代操作,那么到底什么是可迭代对象,本小节主要讨论可迭代对象,首先我们先回顾一下目前我们所熟知的可迭代对象有哪些?

        str,list,tuple,dict,set ,那为什么我们可以称他们为可迭代对象呢?因为他们都遵循了可迭代协议,什么是可迭代协议?首先看一段代码

      

    # 对的
    s = 'abc'
    for c in s:
        print(c)
    
    # 错的
    for i in 123:
    
        print(i)
    # 结果:
    '''
    a
    b
    c
    Traceback (most recent call last):
      File "F:/爬虫/函数.py", line 28, in <module>
        for i in 123:
    TypeError: 'int' object is not iterable
    '''
     

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

    s = '我是哈哈哥'
    print(dir(s))    # 打印对象中的方法和函数
    print(dir(str))  # 打印类中声明的方法和函数
    
    '''
    ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', 
    '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
    '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith',
    'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace',
    'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split',
    'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'] ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__',
    '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
    '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith',
    'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace',
    'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split',
    'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
    '''

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

      我们发现字符串中可以找到 __iter__ ,list,tuple,dict,set ,range 都有 __iter__ ,这几个数据类型同时也可以进行  for循环

      这是查看一个对象是否是可迭代对象的第一种办法,我们还可以通过 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,Iterable))  # True
    print(isinstance(l_iter,Iterator))   # True

      综上 ----- 我们可以确定,如果对象中有 __iter__函数,那么我们认为这个对象遵循了 可迭代协议,就可以获取到相对应的迭代器,这里的 __iter__ 是帮帮助我们获取到对象的迭代器,我们使用迭代器中的 __next__( 来获取到一个迭代器中的元素,那么我们之前讲的 for 循环 的工作原理到底是什么,还是看下面的代码 ----------

    s = '我是哈哈哥'
    c = s.__iter__()    # 获取迭代器
    print(c.__next__())  # 使用迭代器进行迭代 ,获取一个元素  我
    print(c.__next__())  #
    print(c.__next__())  #
    print(c.__next__())  #
    print(c.__next__())  #

      for 循环的机制 

      

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

      使用 while 循环 + 迭代器来模拟 for 循环

      

    lst = [1,2,3]
    lst_iter = lst.__iter__()
    
    while 1:
        try:
            i = lst_iter.__next__()
            print(i)
        except StopIteration:
            break

      总结:

        iterable:可迭代对象,内部包含 __iter__ () 函数

        iterator : 迭代器 -- 内部包含__iter__()  同时包含 __next__()  

        迭代器的特点:

          1.节省内存

          2.惰性机制

          3.不能反复,只能向下执行

      我们可以把要迭代的内容当成子弹,然后呢?获取到迭代器 __iter__( ),就是把子弹都装在弹夹中,然后发射就是 __next__() 把每一个子弹(元素)打出来,也就是说,for 循环的时候,一开始的时候是 __iter__()来获取迭代器,后面每次取元素都是通过 __next__()来完成的,当程序遇到StopIteration将结束循环

      

  • 相关阅读:
    均匀分布的随机数
    第三十四章 软件工艺的话题
    第三十三章 个人性格
    MySQL常用命令(三)---最值的搜索
    lnmp环境运行laravel open_basedir restriction in effect 问题
    Host 'XXX' is not allowed to connect to this MySQL server解决方案
    CentOS 7中设置PHP7的Log文件日志
    如何查看Laravel版本号的三种方法
    CentOS 7下安装Composer + Laravel
    LNMP一键安装包
  • 原文地址:https://www.cnblogs.com/wenqi2121/p/11194404.html
Copyright © 2011-2022 走看看