• 迭代对象与迭代器,for循环本质引申生成器知识(含面试题),常用内置方法(***)以及面向过程编程


    今日内容


     

    迭代器, 可迭代对象, 迭代器对象, for循环内部原理, 生成器, 面试题, 生成器表达式, 内置函数补充, 面向过程编程

    迭代器


     

    什么是迭代器?

    • 迭代:更新换代(重复)的过程,每次迭代都必须基于上一次的结果
    • 迭代器:迭代取值的工具

    为什么要用迭代器?

    • 迭代器给你提供了一种不依赖于索引取值的方式

    如何用迭代器?

    # 重复且每次迭代都是基于上一次结果而来的
    
    l = [1,2,3,4]
    
    n = 0
    
    while n < len(l):
    
        print(l[n])
    
        n += 1

    需要迭代取值的数据类型 : 字符串/列表/元祖/字典/集合

     

    可迭代对象


     

    定义:只要内置有__iter__方法,或者__next__方法的都叫做可迭代对象

    补充:针对双下划线开头/双下划线结尾的方法,我们推荐用 双下 + 方法名来读

    基本数据类型中,可迭代对象有:

    • str,list,tuple,set,dict
    • 文件对象(执行内置的iter后还是它本身,没有出现任何变化)

    注意 :

    • 文件对象本身就是可迭代对象
    • 文件对象为f = open('XXX.txt', 'w', encoding='utf-8')
    • 可迭代对象执行内置的__iter__方法后得到的就是该对象的迭代器对象
    l = [1,2,3,4]
    
    # 生成一个迭代器对象
    
    iter_1 = l.__iter__()
    
    # 迭代器取值,调用__next__
    
    print(iter_l.__next__())
    
    print(iter_l.__next__())
    
    print(iter_l.__next__())
    
    print(iter_l.__next__())
    
    # 取完了之后就报错------StopIteration

     

    迭代器对象


     

     

    定义:

    • 1.内置有__iter__方法
    • 2.内置有__next__方法

    ps:迭代器一定是可迭代对象,而可迭代对象不一定是迭代器对象

    注意点:可迭代对象仅仅内置有__iter__方法

    迭代取值:

    • 优点:
      • 1.不依赖于索引取值
      • 2.内存中永远只占一份空间,不会导致内存溢出
    • 缺点:
      • 1.不能够获取指定的元素
      • 2.取完之后会报错----StopIteration

    例子:

    d = {'name':'jason','password':123,'hobby':'XXX'}
    
    # 将可迭代对象d转换为迭代器对象
    
    iter_d = d.__iter__()
    
    # 迭代器对象的取值,必须用__next__
    
    print(iter_l.__next__())
    f = open('xxx.txt', 'w', encoding='utf-8')
    
    # 调用f内置的__iter__方法
    
    iter_f = f1.__iter__()
    
    print(iter_f1 is f)

    迭代器对象执行__iter__方法之后得到的还是迭代器对象本身(重要)

    思考:__iter__方法就是用来帮我们生成迭代器对象,而文件对象本身就是迭代器对象,为什么还内置iter方法?


     

     小技巧:

    d = {'name':'jason','password':123,'hobby':'XXX'}
    
    iter_d = d.__iter__()
    
    print(iter_d.__next__())
    
    # 异常处理
    
    while True:
    
      try:
    
      print(iter_d.__next__())  # 这段代码是可能会报的错
    
    except StopIteration
    
      print('取值已到达上限')
    
      break

    文件对象迭代取值:

    f = open('XXX.txt', 'r', encoding='utf-8')
    
    iter_f = f.__iter__()
    
    print(iter_f.__next__())

    迭代器取值的特点:

    • 只能往后依次取,不能往回取值

    常规错误点:避免出现print(d.iter().next()),因为它每次都重新开始一段新的迭代

     

    for循环的本质


     

    常规:

    d = {'name':'jason','password':123,'hobby':'XXX'}
    
    for i in d:
    
        print(i)

    试试能否将l迭代:

    for i in l:
    
        pass
    
    iter(l)

    注意点:for 循环后面的in, 跟的必须是一个可迭代对象,否则会报错------object is not iterable

    for 循环内部的本质:

    • 1.将in后面的对象调用__iter__转换成迭代器对象
    • 2.调用__next__迭代取值
    • 3.内部有异常捕获StopIteration,当用__next__取值时报这个错,则自动结束循环
    l1 = [1,2,3,4]
    
    l2 = ['a','b','c','d']
    
    print(zip(l1,l2))  # 这其实就是一个迭代器------返回结果为<zip object at 内存地址>

    生成器:


     

    定义:用户自定义的迭代器,本质就是迭代器

    def fun():
    
        print('first')
    
        yield  # 函数内如果有yield关键字,那么加括号执行函数的时候并不会触发函数体代码的运行
    
    func()  # 运行结果为空,但是能够初始化生成器,将函数变成迭代器

    如果加上g = func():

    def fun():
    
        print('first')
    
        yield
    
    g = func()
    
    g()  # 这时候就能够执行函数体代码了

    这时候用__next__取值:

    def fun():
    
        print('first')
    
        yield 1  # yield后面跟的值就是调用迭代器next后,你能够得到的值
    
    g = func()
    
    print(g)  # <generator object func at 内存地址>
    
    print(g.__next__())  # 返回结果是 1

    yield返回多个值的例子:

    def fun():
    
        print('first')
    
        yield 666,777,888  # yield既可以返回一个值也可以返回多个值,并且多个值也是按照元祖的形式返回
    
    g = func()
    
    print(g.__next__())  # 返回结果是(666,777,888)

    yield有暂停执行的作用:

    def fun():
    
        print('first')
    
        yield 1
    
        print('second')
    
        yield 2
    
        print('third')
    
        yield 3
    
        yield
    
        yield
    
    g = func()
    
    print(g.next())  # 返回结果是 first 1 
    
    print(g.next())  # 返回结果是 first 1 second 2 
    
    print(g.next())  # 返回结果是 first 1 second 2 third 3 
    
    print(g.next())  # 返回结果是 first 1 second 2 third 3 None
    
    print(g.next())  # 返回结果是 first 1 second 2 third 3 None None

    为 for i in range(1,10,1):  

      print(i) 创建一个自定义生成器

    def my_range(start,end,step=2):
    
        while start < end:
    
            yield start
    
            start += step
    
    for j in my_range(1,10,2):
    
        print(j)

    yield表达式形式:

    注意点:yield支持外界为其传参

    def dog(name)
    
        print('%s 准备开吃'%name)
    
        while True:
    
            food = yield
    
            print('%s 吃了 %s'%(name,food))
    
    # 当函数内有yield关键字时,调用该函数不会执行函数体代码,而是将函数变成生成器
    
    g = dog('egon')
    
    g.next()  # egon 准备开吃
    
    res = g.next()  # 返回值为yield,且必须先将代码运行至yield,才能为其传值
    
    g.send('狗不理包子')  # 给yield左边的变量传参,触发了next方法
    
    g.next()  # egon 吃了狗不理包子

    yield:

    • 1.帮你提供了一种自定义生成器方式
    • 2.帮你将函数的运行状态暂停住
    • 3.可以返回值

    return之间异同点:

    • 相同点:
      • 都可以返回值,并且都可以返回多个值
    • 不同点:
      • yield可以返回多次值,而return只能返回一次函数立即结束
      • yield还可以接收外部传入的值

     

    生成器表达式:


     

    res = [i for i in range(1,10) if i != 4]
    
    print(res)  # [1,2,3,5,6,7,8,9]
    res = (i for i in range(1,10) if i != 4)  # 生成器表达式
    
    print(res)  # <generator ogject <genexpr> at 内存地址>,它本质上是一个生成器 
    print(res.__next__())  # 返回结果为1,再往后就依次返回2,3,5...

    下面两种方式,前者太占用内存,而后者则是改进版本:

    f = open('XXX.txt', 'r', encoding='utf-8')
    
    data = f.read()
    
    print(len(data))
    
    f.close()
    with open('XXX.txt', 'r', encoding='utf-8') as f:
    
        n = 0
    
        for line in f:
    
            n += len(line)
    
    print(n)

    在上述改进版本中,用迭代器的知识点来提高效率:

    with open('XXX.txt', 'r', encoding='utf-8') as f:
    
        g = (len(line) for line in f)  # 这行代码本质上是一个迭代器
    
        print(sum(g))  # 将print(g.next())替换掉了

    注意点:

    • 生成器不会主动执行任何一行代码
    • 必须通过__next__触发代码的运行

     

    面试题目1(重要):


     

    def add(n,i):
    
        return n + i
    
    def test():
    
        for i in range(4):
    
            yield i
    
    g = test()
    
    for n in [1,10]:
    
        g = (add(n,i) for i in g)  # 此段代码循环结束后,n = 10
    
    # 第一次for循环,g = (add(n,i) for i in test())
    
    # 第二次for循环,g = (add(n,i) for i in (add(n,i) for i in test()))
    
    res = list(g)  # 返回值结果为[20,21,22,23]
    
    # 其中list(g),括号内部是基于for循环的
    
    # 等价于for i in (add(n,i) for i in test()):
    
    # 得到 n = 10 后,再代入add(n,i)计算结果
    
    # 另外补充一点, in后面跟生成器,就会触发 生成器
          

     

    面试题目2(重要):


     

    def multipliers():
    
        return [lambda x: i*x for i in range(4)]
    
    print([m(2) for m in multipliers()])  # [6,6,6,6]

    至于为何返回值不是[0,2,4,6],

    原因:闭包函数的延迟绑定----在内层函数执行时才会绑定变量i

    # 将上段代码用常用闭包函数的形式表达出来
    
    def multipliers():
    
        list1 = []
    
        for i in range(4):
    
            def func(x):
    
                return x*i
    
            list1.append(func)
    
        return list1
    
    print([m(2) for m in multipliers()])  # [6,6,6,6]
    def multipliers():
    
        list1 = []
    
        for i in range(4):
    
            def func(x,i=i):  # 第一个i是func函数的默认参数,第二个i是上面函数的i
    
                return x*i
    
            list1.append(func)
    
        return list1
    
    print([m(2) for m in multipliers()])  # [0,2,4,6]
    
    # 这时就不存在闭包函数的延迟绑定了

    面试题目3:


    需求:读取一个文件并返回每行数据的长度

    1.常规解决方法:

    with open('test1.txt', 'w', encoding='utf-8') as f:
    
        for line in range(1000):
    
            f.write(f'www{line}aaa' * (line + 1) + '
    ')

    2.列表推导式(可处理数据量小的数据,若处理数据量大的文件会导致内存溢出)

    res1 = [len(line) for line in open('test1.txt', 'r', encoding='utf-8')]
    
    print(res1)

    3.生成器表达式:处理数据量大的文件推荐使用

    res2 = (len(line) for line in open('test1.txt', 'r', encoding='utf-8'))
    
    print(res2)  # <generator object <genexpr> at 内存地址>
    
    print(next(res2))  # 开始返回值8 15 22 ...(依次加7)

    面试题目4:


    def demo():
    
        for i in range(4):
    
            yield i
    
    g = demo()  # <gen...>1 (0,1,2,3)
    
    g1 = (i for i in g)  # <gen...>2 (0,1,2,3)
    
    g2 = (i for i in g1)  # <gen...>3 
    
    print(list(g1))  # [0,1,2,3],这时候list()已经将所有值都获取出来了
    
    print(list(g2))  # []

    常用内置方法补充:


     

    abs

    print(abs(-11,11))  # 求绝对值

    all,any

    l = [0,1,2]
    
    print(all(l))  # False,----只要有一个为Flase就返回Flase
    
    print(any(l))  # True,----只要有一个为True就返回True

    bin,oct,hex

    print(bin(10))  # 0b1010------将10进制转化为二进制
    
    print(oct(10))  # 0o12------将十进制转化为八进制
    
    print(hex(10))  # 0xa------将十进制转化为十六进制

    bool

    print(bool(1))  # True
    
    print(bool(0))  # False

    encode,bytes

    s = 'hello'
    
    print(s.encode('utf-8'))  # b'hello' 
    
    print(bytes(s,encoding='utf-8'))  # b'hello' 

    callable:可调用的(可以加括号执行相应功能的)

    1 = [1,2,3]
    
    def index():
    
        pass
    
    print(callable(l))  # False
    
    print(callable(index))  # True

    chr:将数字转换成ASCLL码表对应的字符

    # 将数字转换成ASCLL码表对应的字符
    
    print(chr(65))  # A
    
    print(chr(97))  # a

    ord:

    # 将字符按照ASCLL转换为对应的数字
    
    print(ord('a'))  # 97

    面向对象需要学习的方法:

    classmethod  delattr  getattr  hasattr  issubclass  property  repr  setattr  super  staticmethod

    dir: 获取当前对象名称空间里所有它支持的名字

    l = [1,2,3]
    
    print(dir(l))

    divmod: 分页器

    print(divmod(100,11))  # (9,1) 9页余1
    
    # 例子:
    
    total_num,more = divmod(101,10)
    
        if more:
    
            total_num += 1
    
    print('总页数:',total_num)  # 总页数:82页

    enumerate :枚举

    l = ['a','b']
    
    for i,j in enumerate(1,l):
    
        print(i,j)
    
    # 1 a
    
    # 2 b

    eval :只能识别简单的python代码,不支持逻辑代码

    exec :能够帮你识别字符串中的代码,然后执行(包括逻辑类代码)

    s = " " "
    
    print('hello baby~')
    
    print(1 + 2)
    
    " " "
    
    eval(s)  #  'hello baby~' 3 
    
    # 或者
    
    name = 'jason'
    
    s = " " "
    
    name
    
    " " "
    
    print(eval(s))  # 'jason'

    format三种玩法

    • {}占位
    • {index}索引占位
    • {name}指名道姓

     globals,locals

    print(globals())  # 无论在哪都是将当前所有全局空间变量名打印出来
    
    print(locals())  # 将当前所在的局部空间变量名打印出来,当前语句在哪个位置,就会返回哪个位置所存储的所有的名字

    help

    def login():
    
    " " "
    
    XXX
    
    :resturn:
    
    " " ''
    
    print(help(login))  # 显示注释

    isinstance

    n = 1
    
    print(type(n))
    
    print(isinstance(n,list))  # 推荐的统一用法 : 判断对象是否属于某个数据类型
    
    print(type(n)) is int)  # 以前的常规判断方法

    pow

    print(pow(10,3))  # 10的3次方

    round:四舍五入

    print(round(3.49))  # 3
    
    print(round(3.51))  # 4

    面向过程的编程


     

    面向过程编程 : 类似于设计一条流水线

    • 优点:
      • 将复杂的问题流程化,从而简单化
    • 缺点:
      • 可扩展性比较差,一旦需要修改,整体都会收到影响

     

    例子 : 注册功能的实现

    1.获取用户输入:

    def get_info():
    
        while True:
    
            username = input('>>>:').strip()
    
            if username.isalpha(): '''判断字符串必须是字母'''
    
                print('不能包含数字')
    
                continue
    
            password = input('>>>:').strip()
    
            confirm_password = input('confirm>>>:').strip()
    
            if password == confirm_password:
    
                d = {
    
                       '1':'user',
    
                        '2':'admin'
    
                }
    
                while True:
    
                    print("""
    
                        1 普通用户
    
                        2 管理员
    
                    """)
    
                    choice == input('please choice user type to register>>>:').strip()
    
                    if choice not in d:continue
    
                    user_type = d.get(choice)
    
                    operate_data(username,password,user_type)
    
                    break
    
                else:
    
                    print('两次密码不一致')

    2.处理用户信息:

    def operate_data(username,password,user_type):
    
        res = '%s|%s|%s
    '%(username,password,user_type)
    
        save_data(res,'userinfo.txt')

    3.存储到文件中:

    def save_data(res,file_name):
    
        with open(file_name, 'a', encoding='utf-8') as f:
    
            f.write(res)

    4.合成功能:

    def register():
    
        get _info()
    
    register()

     

  • 相关阅读:
    Java static 静态代码块、代码块
    blog
    Java 类之间的关系
    vscode Cannot edit in read-only editor.
    以KNN为例用sklearn进行数据分析和预测
    Python 时间处理
    Python map filter reduce enumerate zip 的用法
    Python列出文件夹中的文件
    Java类只加载一次的情况
    Powershell 中的管道
  • 原文地址:https://www.cnblogs.com/zhukaijian/p/11191828.html
Copyright © 2020-2023  润新知