代码改变世界

上海day13 -- 迭代器,生成器以及常用内置方法

2019-07-15 17:32  在上海的日子里  阅读(228)  评论(0编辑  收藏  举报

目  录

一、迭代器

二、for 循环原理

三、生成器

四、常用内置方法

 

一、迭代器

解释:迭代就是在前一次的结果上重复取值,器就是工具。迭代器就是迭代取值的工具。

1、为什么要用迭代器?

  迭代器不需要依赖索引取值。

2、可迭代对象:

  内置只有__iter__方法的叫做可迭代对象。

3、迭代器对象:

  内置不仅有__iter__方法,还有__next__方法的叫做迭代器对象。

注意:可迭代对象通过__iter__方法得到迭代器对象,迭代器对象通过__next__方法取值。

4、基本数据类型有哪些可迭代对象?

  可迭代对象即内置有__iter__方法的数据类型,

1 # n = 1
2 # f = 1.1
3 s = 'hello'
4 l = [1,2,34,]
5 t = (1,2,34)
6 s1 = {1,2,3,4}
7 d = {'name':'jason'}
8 f1 = open('xxx.txt','w',encoding='utf-8')

以上实验可知:str, list, dict, tuple, set, f  都内置有__iter__方法,

       特别是文件对象f 不仅有 __iter__方法还有__next__方法,说明文件对象不仅是可迭代对象还是迭代器对象。

补充小知识:

  针对双下划线开头双下划线结尾的方法,python推荐读法:双下+方法名

  Python解释器为我们定制了快捷方法来代替双下划线__:

    __iter__ 等价于 iter()

    __len__ 等价于 len()

    __next__ 等价于 next()

5、迭代器取值

迭代器取值特点:

  a、前面提到过迭代器取值只能通过__next__方法。每执行一次就提取一行内容,若容器中没有可取值会报错:StopIteration

  b、只能往后一次取,不能后退。

注意:文件对象及是可迭代对象又是迭代器对象

f1 = open('xxx.txt','r',encoding='utf-8')
# 调用f1内置的__iter__方法
# iter_f = f1.__iter__()
# print(iter_f is f1)

由以上代码可知:文件对象f 调用 __iter__方法得到是自己本身。

提出问题:为什么文件对象是迭代器对象还会有__iter__方法?

解决问题--引出:for循环原理 --  for 循环后面的in 若接的是迭代器对象,但迭代器对象没有__iter__方法的话会for循环会报错!

得出结论如下:

  迭代器对象无论执行哪个多少次__iter__方法都是得到迭代器对象自己本身。(******)

6、总结:

  可迭代对象内置只有__iter__方法;

  迭代器对象既有__iter__方法,也有__next__方法;

  迭代器对象一定是可迭代对象,但可迭代对象不一定是迭代器对象。

二、for 循环内部原理

d = {'name':'jason','password':'123','hobby':'泡m'}
 for i in d:
     print(i)
# for循环后面的in关键 跟的是一个可迭代对象

for 循环内部的本质:

  1、将 in 后面的对象通过 调用__iter__方法转成迭代器对象;

  2、调用__next__方法迭代取值;

  3、一直迭代取值,直到容器为空,报错。然后捕获异常StopIteration,当 __next__方法报错,自动结束循环。

注意:由上可知,for循环后 in对应的对象是可迭代对象

迭代取值的优缺点:

  优点:1、不依赖索引取值;

     2、内存中永远只出现一行内容,不会导致内存溢出的情况出现。

  缺点:1、不能指定取值;

     2、当取值为空时,会报出StopIteration 的错误。

三、生成器

1、生成器:

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

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

2、自定义迭代器完成range()方法

def my_range(start,end,step=1):
    while start < end:
        yield start
        start += step

for j in my_range(1,100,2):
    print(j)

3、生成器表达式  -- 就是元组括号:例如:res = (i  for i in range(5))  得到生成器对象。

res3 = range(10)
print(res3)  # range(0, 10)

res2 = [i for i in range(10)]
print(res2)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

res = (i for i in range(10))
print(res)  # <generator object <genexpr> at 0x01A2D0F0> 得到一个生成器对象
print(res.__next__())  # 0
print(res.__next__())  # 1
"""
由上可知:
    生成器不会主动执行任何一行代码
    必须通过__next__触发代码的运行
"""

4、yeild 关键字的特点、与return的区别等

特点:1、返回值与return一样可以返回一个值,也可以返回多个值,多个值以元组形式返回;

      2、暂存函数的运行状态,

     3、可以通过外接传参 (前提是代码运行到yeild的位置,才可以通过send方法传参)

     args = yeild 111

    send方法通过外界传参之后会自动运行下一句代码。

 区别:yeild 可以执行多次,return执行一次之后函数就会结束。

5、重点!!!面试题~

 解题思路:

 

 

四、常用的内置函数

abs() 求绝对值

# abs 求绝对值
print(abs(-1.11))  # 1.11

all() any() 返回布尔值

# all() any() 返回布尔值
li = [0,2,34,5]
print(all(li))  # False  容器里面的元素全为True才返回True
print(any(li))  # True   容器里面只要有一个元素为True 就返回True

globals()  locals()

def func():
    user_name = '我是局部名称空间'
    print(locals())  # 返回当前位置所存储的名称空间的名字  {'user_name': '我是局部名称空间'}
    print(globals())  # 无论在什么位置,返回的都是全局名称空间的名字
func()

bin() oct() hex() 十进制转其他进制, int('其他进制字符',进制数) 其他进制转十进制

bytes() 字符编码转换的两种形式

# bytes() 字符编码转换两种方式
x = '上海'
print(x.encode('utf-8'))
print(bytes(x,encoding='utf-8'))

callable()

# callable() 是否可调用...
list2 = [1,2,3,4]
def index():
    pass
print(callable(list2))  # False
print(callable(index))  # True

chr()  ord()   ASCII码表对应字符与数字的转换

# chr() ord()  ASCII码表对应字符与数字的转换
print(chr(97))  # a  将ascii码表对应数字转为字符
print(ord('a'))  # 97  将ASCII码表对应字符转为数字

dir() 获取当前名称空间里的名字    /  主要用于模块中名称空间名字的查找

# dir() 获取当前名称空间里的名字  /主要用于模块中名字变量的查找
list3 = [23,34,45,66]
print(dir(list3))  # 好多。。。

divmod() 分页器

# divmod() 分页器
print(divmod(121,10))  # (12, 1) 返回整除数和余数
# 网站分页的实现:
num1, num2 = divmod(121,10)
if num2:
    num1 += 1
print('当前需要的页数为:%s'%num1)  # 当前需要的页数为:13

enumerate() 枚举

# enumerate() 枚举
list3 = ['jason','tank','egon']
for i ,j in enumerate(list3):
    print(i,j,end=' ')  # 0 jason 1 tank 2 egon 默认索引从0开始
for i ,j in enumerate(list3,1):
    print(i,j,end=' ')  # 1 jason 2 tank 3 egon  设置索引从1开始

eval()   exec()   可以执行字符串内的代码

# eval() exec()
str1 = """
print('hello world')  # 注意:要顶格对齐!!!
x = 1
y = 2
print(x+y)
"""
#eval(str1)  # 报错! eval()只能运行简单的代码,不能进行逻辑运算
exec(str1)  # hello world  3
# eval()需要注意的示例
name = 'jason'
s2 = """
name
"""
print(eval(s2))  # jason

format() 格式化输出,三种玩法

  和%s一样{}占位,{index}索引,{name}指名道姓即关键字传参

isinstance() 判断对象是否属于某种数据类型   /  推荐使该方法

# isinstance()
n = 'adads'
print(isinstance(n,str))  # True
print(isinstance(n,dict))  # False

pow()    幂次方相乘

# pow()
print(pow(3,2))  # 9   3的平方

round()   四舍五入进位整数

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