python迭代器-迭代器取值-for循环-生成器-yield-生成器表达式-常用内置方法-面向过程编程-05

  • 2019 年 10 月 7 日
  • 筆記

迭代器

迭代器

迭代: # 更新换代(其实也是重复)的过程,每一次的迭代都必须基于上一次的结果(上一次与这一次之间必须是有关系的)

迭代器: # 迭代取值的工具

为什么用迭代器: # 迭代器提供了一种可以不依赖索引取值的方式

# 会一直打印0,记得停止  # n = 0  # while True:  #     print(n)    # 重复 + 每次迭代都是基于上一次的结果而来的  l = [1, 2, 3, 4, 5]  s = 'hello'  n = 0  while n < len(s):      print(s[n])      n += 1  # h  # e  # l  # l  # o

可迭代对象

'''  可迭代对象      只要内置有 __iter__ 方法的都叫做可迭代对象(读:双下iter)          补充: 针对双下划线开头结尾的方法,推荐读“双下 + 方法名”      基本数据类型中,是可迭代对象的有(str, list, tuple, dict, set), 文件对象(执行 __iter__ 之后还是本身,__next__之后还是他本身)        可迭代对象执行内置的 __iter__ 方法,得到的就是该对象的迭代器对象  '''
n = 1  f = 1.1  s = 'hello'  l = [1,2,34,]  t = (1,2,34)  s1 = {1,2,3,4}  d = {'name':'jason'}  f1 = open('xxx.txt','w',encoding='utf-8')    #  # res = s.__iter__()  # res = iter(s)  #  # print(s.__len__())  # 简化成了len(s)  # res1 = l.__iter__()  # res1 = iter(l)  # res2 = f1.__iter__()  # res2 = iter(f1)  # print(res,res1,res2)  # print(f1)    # 可迭代对象执行内置的__iter__方法得到就是该对象的迭代器对象

迭代器对象与可迭代对象的区别

'''  迭代器对象和可迭代对象有什么共同点      迭代器对象          1.内置有双下iter( __iter__) 方法          2.内置有 __next__ 方法          ps:迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象  '''

__iter__转换迭代器对象

l = [1, 2, 3, 4]  # 生成一个迭代器对象  iter_l = l.__iter__()    # 迭代器取值 调用__next__  print(iter_l.__next__())  print(iter_l.__next__())  print(iter_l.__next__())  print(iter_l.__next__())  # 1  # 2  # 3  # 4  # print(iter_l.__next__())  # 取完了 直接报错      d = {'name':'jason','password':'123','hobby':'泡m'}  # 将可迭代对象d转换成迭代器对象  iter_d = d.__iter__()  # 迭代器对象的取值 必须用__next__  print(iter_d.__next__())  print(iter_d.__next__())  print(iter_d.__next__())  # name  # password  # hobby  # print(iter_d.__next__())  # 取完了 报错StopIteration    f1 = open('test1.txt', 'r', encoding='utf-8')  # 调用f1内置的__iter__方法  iter_f = f1.__iter__()  print(iter_f is f1)  # True  """  迭代器对象无论执行多少次__iter__方法得到的还是迭代器对象本身(******)  """  print(f1 is f1.__iter__().__iter__().__iter__().__iter__())  # True

# 迭代器对象无论执行多少次__iter__方法得到的还是迭代器对象本身(******)

疑问: # __iter__方法就是用来帮我们生成迭代器对象,而文件对象本身就是迭代器对象,为什么还内置有__iter__方法??? —见for循环原理

异常处理

d = {'name': 'jason', 'password': '123', 'hobby': '泡m'}  iter_d = d.__iter__()  # 异常处理  while True:      try:          print(iter_d.__next__())      except StopIteration:          print('老母猪生不动了')          break  # name  # password  # hobby  # 老母猪生不动了

迭代器与迭代器对象总结

'''  可迭代对象:内置有 __iter__ 方法  迭代器对象:既内置有__iter__ 方法,也内置有__next__方法    迭代取值的优点与缺点:      优点:          不依赖于索引取值          内存中永远只占一份空间,不会导致内存溢出      缺点:          不能获取指定的元素          取完之后会报StopIteration错..  '''

for循环内部原理

'''  for 循环内部的本质      1.将in后面的对象调用 __iter__ 转换成迭代器对象   --> 所以前面的疑问,文件对象本来就是迭代器对象还有 __iter__ 方法      2.调用__next__ 迭代取值      3.内部有异常捕获,StopIteration,当__next__报这个错,自动结束循环  '''

 内部原理同上面异常处理里的案例

生成器

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

注意点: # 函数内如果有yield关键字,那么加括号执行函数的时候并不会触发函数体代码的运行 , # yield后面跟的值就是调用迭代器__next__方法你能得到的值 , # yield既可以返回一个值也可以返回多个值 并且多个值也是按照元组的形式返回

 yield 返回值(体现上面的注意点)

def func():      print('first')      yield  # 函数内如果有yield 关键字,那么加括号执行函数的时候并不会触发函数体代码的运行  ***      print('second')      yield 2  # yield 后面跟的值就是调用迭代器 __next__ 方法你能得到的值      print('third')      yield 3, 4, 5  # 既可以返回一个值,也可以返回多个值,并且多个值也是按照元组的形式返回      g = func()  # 生成器初始化:将函数变成迭代器  # g.__iter__()  print(g.__next__())  # first  # None    print(g.__next__())  # second  # 2    print(g.__next__())  # third  # (3, 4, 5)

小案例

# 自定义range 功能  for i in range(10):      print(i, end='- ')  print()      def my_range(start, end, step=1):  # 只传一个参数的,range,判断参数个数  搜:python只传一个参数的range      while start < end:          yield start          start += step      for i in my_range(1, 10, 3):      print(i)  # 1  # 4  # 7

yield表达式形式传入参数

# yield 表达式形式(传参的第三种方式,直接传参,闭包)  def dog(name):      print("%s 准备开始吃" %name)      while True:          food = yield          print("%s 吃了 %s" %(name, food))      print(dog)  # <function dog at 0x000001C22A10BA60>    # 当函数内有yield 关键字的时候 调用该函数 不会执行函数体代码  #   而是将函数变成生成器  g = dog("egon")  # 把函数变成生成器,函数体没有运行  g.__next__()  # 不运行这个直接运行下面的会直接报错 TypeError: can't send non-None value to a just-started generator  # 必须将代码运行至 yield 才能为其传值  # egon 准备开始吃  g.send('狗不理包子')  # 给yield 左边的变量传参,触发了 __next__ 方法  # egon 吃了 狗不理包子  g.__next__()  # egon 吃了 None  g.send('饺子')  # egon 吃了 饺子

总结yield并与return作对比

'''  总结yield:      1.yield 提供了一种自定义生成器的方式      2.yield 会帮你将函数的运行状态暂停住      3.yield 可以返回值    与return 之间的异同点:      相同点:          1.都可以返回值,并且都可以返回多个,返回多个都是包装成元组      不同点:          1.yield 可以返回多次值,而return  只能返回一次函数立即结束          2.yield还可以接收外部传入的值    '''

常用内置方法

常见数学内置函数 abs 绝对值      pow 求平方    round  四舍五入   divmod 将运算结果除数与余数存入元组

# abs 求绝对值  print(abs(-10.11))  # 10.11    # pow 平方  print(pow(2, 4))  # 16    # round 四舍五入  print(round(3.1656))  # 3    # divmod 将运算结果除数与余数存入元组(可用于分页器)  print(divmod(100, 11))  # (9, 1)  all_count = 101  counts_each_page = 5  total_pages, more = divmod(all_count, counts_each_page)  if more:      total_pages += more  print(total_pages)  # 21  --> 共101条内容,按每页5条来分,需要分21页

数据类型进制转换  isinstance(判断数据类型)  all(传过来容器类型必须全部都是True才返回True)   any(有一个是True就返回True)   bool(将传进来参数变成布尔类型)   bin(十转二) oct(十转八)  hex(十转十六)    int(把指定类型转成十进制)

# isinstance 判断数据类型,后面统一用该方法判断对象是否属于某一个数据类型  n = 1  print(type(n))  print(isinstance(n, list))  # 判断对象是否属于某个数据类型  # <class 'int'>  # False    # all 传过来的容器类型里必须全部是True,否则返回False  # any 只要一个True,就返回True  l = [0, 1, 2]  print(all(l))  # 只要有一个是False,就返回False  print(any(l))  # False  # True    # bool  print(bool(1))  print(bool(0))  # True  # False      # bin  oct  hex 将十进制转换成对应的进制  print(bin(10))  print(oct(10))  print(hex(10))  # 0b1010 二进制  # 0o12 八进制  # 0xa 十六进制    # int 可以把指定进制转成十进制  print(int('0b1010', 2))  # 10

字符编码  ascii (个人觉得没啥用)  chr(将数字转换成ascii码 对应的字符)    ord (将字符按照ascii码 转成数字)  bytes(转成二进制)

# ascii  个人觉得没啥用  print(ascii('a'))  # 'a'  print(ascii(65))  # 65  print(ascii('c'))  # 'c'    # chr  ord 将数字转换成ascii 码表对应的字符  将字符按照ascii 码表转成对应的数字  print(chr(65))  # A  print(ord('A'))  # 65    # bytes 转换成二进制  # s = b'hello'  # print(s)  # # b'hello'  s = 'hello'  print(s.encode('utf-8'))  print(bytes(s, encoding='utf-8'))  # b'hello'  # b'hello'

可迭代对象常见内置函数  slice  切片(生成的是老母猪,节省空间)  enumerate  给可迭代对象生成索引(假索引)

# slice 切片  myslice = slice(5)    # 设置截取5个元素的切片  arr = range(10)  print(arr)  print(arr[myslice])  # 截取5个元素  print(arr)  # range(0, 10)  # range(0, 5)  # range(0, 10)      # enumerate 枚举 可以指定起始位  l = ['a', 'b', 'c']  for i, j in enumerate(l, 1):      print(i, j)  # 1 a  # 2 b  # 3 c

执行字符串中的python语句以及python字符串格式化  eval (执行字符串中的python语句,不够强大)   exec (执行python中的语句,能执行逻辑的)   format(格式化字符串)

# eval  exec 执行字符串里的代码,eval 不支持逻辑代码,只支持一些简单的python代码, exec可以执行逻辑代码  s = """  print('hello baby~')  # x = 1  # y = 2  # print(x + y)  """    # eval(s)  # hello baby~  exec(s)  # hello baby~    # format 三种玩法  # ------ {} 占位 --------  print('{} like {}'.format('tank', 'jason'))  # tank like jason  # ------ {index} 索引 --------  print('{0} like {2}'.format('tank', 'egon', 'jason'))  # tank like jason  # ------ {name} 指名道姓(关键字) --------  print('{name} is {age} years old.'.format(age=18, name='jason'))  # jason is 18 years old.

对象命名空间 callable(对象是否可调用)  dir (获取该对象名称空间里的名字)  globals (查看全局名称空间的名字)    locals (返回当前位置名称空间的名字)  help (查看函数的注释)

# callable 可调用的,可以加括号执行相应功能  def index():      pass  l = [1, 2, 3, 4, 5]  print(callable(index))  print(callable(l))  # True  # False    # dir 获取当前对象名称空间里面的名字(所有他能够支持的名字),可以是任何对象  l = [1, 2, 3]  print(dir(l))  # ['__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']  # import test  # print(dir(test))  # print(test.name)      # globals 无论在哪,查看的都是全局名称空间  # locals 当前语句在那个位置,就会返回哪个位置所存储的所有名字  def index():      '''      index的注释      :return: 没有返回值      '''      username = "局部名称空间里的username"      print(locals())  # 当前语句在那个位置,就会返回哪个位置所存储的所有名字      print(globals())  # 不受位置影响  # {'__name__': '__main__'-------省略一大堆------- 'l': ['a', 'b'], 'i': 2, 'j': 'b'.....>}  index()  # {'username': '局部名称空间里的username'}      # help 查看函数注释  print(help(index))  # Help on function index in module __main__:  #  # index()  #     index的注释  #     :return: 没有返回值  #  # None

面向过程编程

概述: # 面向过程就类似于流水线设置,将复杂问题分步实现

优点: # 可以将复杂的问题流程化,从而简单化

缺点: # 可扩展性差,如有改动,可能会涉及超大面积更改

小案例(牵一发动全身)

# 获取用户登录  def get_info():      while True:          username = input(">>>:").strip()          if not username.isalpha():  # 判断字符串不能包含数字              print('不能包含数字')              continue          password = input('>>>:').strip()          confirm_password = input("confirm>>>:").strip()          if password == confirm_password:              operate_data(username,password)              break          else:              print('两次密码不一致')    # 2.处理用户信息  def operate_data(username,password):      # jason|123      res = '%s|%sn'%(username,password)      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)    def register():      get_info()    register()
# 在用户注册时候让用户选择用户类型  # 1.获取用户输入  def get_info():      while True:          username = input(">>>:").strip()          if not 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):      # jason|123      # 拼接也要改动 ------------------------------------------      res = '%s|%s|%sn'%(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)    def register():      get_info()    register()

 扩展练习题(面试题)

1.请判断下面代码中的 res 是什么

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)  res = list(g)# A. res = [10, 11, 12, 13]  # B. res = [11, 12, 13, 14]  # C. res = [20, 21, 22, 23]  # D. res = [21, 22, 23, 24]
# C. res = [20, 21, 22, 23]

2.请判断下面程序会输出什么

# 已经提前把里面的东西取出来了

3.利用生成器表达式读取文件行数

'''  需求: 读取一个文件并返回每行数据的长度  '''  with open('test1.txt', 'w', encoding='utf-8') as f:      for line in range(1000):          f.write(f'www{line}aaa' * (line + 1) + 'n')
# 列表推导式: 处理数据量大的文件会导致内存溢出.  res = [len(line) for line in open('test1.txt', 'r', encoding='utf-8')]  # print(res)      # 生成器表达式: 处理数据量大的文件推荐使用.  res2 = (len(line) for line in open('test1.txt', 'r', encoding='utf-8'))  print(res2)  # <generator object <genexpr> at 0x000002B3748FD0A0>  print(next(res2))  print(next(res2))

4.写出下面代码的执行结果

# 请写出下面代码的执行结果  def mutipliers():      return [lambda x: i*x for i in range(4)]      print([m(2) for m in mutipliers()])
# [6,6,6,6]  ---> 题目的正确答案  def multipliers():        return [lambda x, i=i: i*x for i in range(4)]      # 0, 1, 2, 3      # [func(x): return 0*x, func(x): return 1*x,      # func(x): return 2*x, func(x): return 3*x, ]    print([m(2) for m in multipliers()])  # [0, 2, 4, 6]    # [func(x): return 0*2, func(x): return 1*2,  # func(x): return 2*2, func(x): return 3*2, ]  # [0, 2, 4, 6]  # [6, 6, 6, 6]    # 闭包函数的延迟绑定  # 在内层函数执行时才会绑定变量i  def multipliers2():      list1 = []      for i in range(4):            def func(x, i=i):                return x * i            list1.append(func)        return list1    print([m(2) for m in multipliers2()])  # [0, 2, 4, 6]    # [0, 2, 4, 6]