首页 > 技术文章 > 生成器,生成器表达式,常见内置函数

gengfenglog 2021-01-04 23:36 原文

生成器

生成器就是一种自定义的迭代器

jianchi


生成器对象

# 定义阶段就是一个普通函数
def func():
    print('first')
    yield 111
    print('second')
    yield 222
    print('third')  # 报错,抛出异常 StopIteration 取到这里就取干净了
'''
当函数内出现yield关键字,再调用函数并不会触发函数体代码的运行,
而是将函数变成了生成器(迭代器)
'''
# 调用函数:不执行函数体代码 而是转换为生成器(迭代器)
g = func()
# print(g)  # <generator object func at 0x7fca46cd2890> 生成器就是一种自定义的迭代器
                                                                                                                  
res = next(g)  # 每执行一个__next__代码往下运行到yield停止 返回后面的数据
print(res)

res = next(g)  # 再次执行__next__接着上次停止的地方继续往后 遇到yield再停止
print(res)

next(g)  # 取不到了报错


# 一出场就是一只老母猪,可以存无穷个值的类型,但每次只能拿一个
def func():
    res = 1
    while True:
        yield res
        res += 1

g = func()  # 得到一个迭代器

print(next(g))  # 打印next触发代码运行,可以返回无数个值
print(next(g))
print(next(g))

自定义range功能

# for i in range(1, 10):  
#     print(i)

# 模仿上面的range()
def my_range(start, stop):  
    while start < stop:
        yield start
        start += 1

res = my_range(1, 10)  # 调用函数:不执行函数体代码,而是转换为生成器(迭代器)

for i in my_range(1, 10):  
    print(i)  # 结果和range效果一样


# 自定义range()模仿的更像一点
def my_range(start, stop=None, step=1):
    if not stop:  # 解决一个参数
        stop = start
        start = 0
    while start < stop:  # 解决二个参数
        yield start
        start += step  # 解决三个参数
        
# 一个数的情况        
res = my_range(10)  # 不执行函数体代码,而是转换为生成器(迭代器)
for i in res: 
    print(i) 

# 两个数的情况
res = my_range(1,10)
for i in res:
    print(i)

# 三个数的情况
res = my_range(1,10,3)
for i in res:
    print(i)

yield传值(了解)

def eat(name):
    print('%s 准备干饭!!!'%name)
    while True:
        food = yield
        print('%s 正在吃 %s' % (name, food))
        
res = eat('jason')  # 并不会执行代码,而是转换成生成器
"""
send与next作用相同,都是进行下一次迭代的意思(都会解阻塞yield关键字)
send可以传递参数表示yield语句的返回值。而next不能传递参数
会先将参数当做yield语句的返回值,然后再解阻塞yield 遍历。(因此不推荐第一次遍历时使用send传参)
"""
res.__next__()
res.send('肉包子')  # send的参数就是yield语句的返回值
res.send('盖浇饭')
'''
jason 准备干饭!!!
jason 正在吃 肉包子
jason 正在吃 盖浇饭
'''

yield与return对比

  • yield

    • 1.可以返回值(支持多个并且组织成元组)

    • 2.函数体代码遇到yield不会结束而是"停住"

    • 3.yield可以将函数 变成生成器 并且还支持外界传值

    • 4.yield可以返回值多次

  • return

    • 1.可以返回值(支持多个并且组织成元组)

    • 2.函数体代码遇到return直接结束

    • 3. return只能返回值一次


生成器表达式

# 把列表生成式的[]换成()就是生成器表达式
res = (i for i in range(3))
print(res)
print(next(res))
print(next(res))
print(next(res))
print(next(res))  # 报错
"""
    迭代器对象,生成器对象,我们都可以看成是"工厂"
    只有当我们所要数据的时候工厂才会加工出"数据"
        上述方式就是为了节省空间
"""

# 统计一个文件里面的字符个数
with open('a.txt',mode='rt',encoding='utf-8') as f:
     res = f.read()
     print(len(res))
    
# 考虑到如果文件过大一次读吗?可采用下面方式
# 方式一:
      res = 0
      for line in f:  # 每次统计一行,不费内存
          res += len(line)
      print(res)

# 方式二:利用内置函数sum,每取一次加一次
# res = sum((len(line) for line in f))
      res = sum(len(line) for line in f)

      print(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)
    """
    第一次for循环
        g = (add(n, i) for i in g)
    第二次for循环
        g = (add(10, i) for i in (add(10, i) for i in g))
    """
res = list(g)
print(res)

# A. res=[10,11,12,13]
# B. res=[11,12,13,14]
# C. res=[20,21,22,23]  √
# D. res=[21,22,23,24]



常见内置函数


1.abs() 函数返回数字的绝对值

print(abs(123))  # 123

print(abs(-123))  # 123

print(abs(10.2))  # 10.2

print(abs(-10.2))  # 10.2

2.all() 用于判断给定的可迭代参数中的所有元素是否都为True,如果是返回True,否则返回False

l = [11, 22, 33, 44]
print(all(l))  # True

l = [11, 22, 33, 0]  # 元素除了是 0、空、None、False外都算True
print(all(l))  # False


l = []  # 注意:空元组、空列表返回值为True,这里要特别注意。
print(all(l))  # True

3.any() 用于判断给定的可迭代参数中的所有元素有一个为True,则返回True,否则返回False

l = [1, 2, 3]
print(any(l))  # True

l = [0, '', None, False]  
print(any(l))  # False

4.bin() 将int转换成二进制 oct() 将int转换成8进制 hex() 将int转换成16进制以字符串形式表示


print(bin(123))  # 0b1111011  转换成二进制

print(oct(123))  # 0o173  将int转换成8进制

print(hex(123))  # 0x7b  将int转换成16进制

5.bytes() 将字符串转换成二进制 str() 将二进制转换成字符串(需指定编码)

res = '哈哈哈'
res1 = bytes(res, 'utf8')
print(res1)  # b'\xe5\x93\x88\xe5\x93\x88\xe5\x93\x88'

res2 = str(res1,'utf8')
print(res2)  # 哈哈哈

# 编码
res1 = res.encode('utf8')  # b'\xe5\x93\x88\xe5\x93\x88\xe5\x93\x88'
print(res1)

# 解码
res2 = res1.decode('utf8')  # 哈哈哈
print(res2)

6.callable() 于检查一个对象是否可调用的,可调用返回 True,否则返回 False

s = 'jason'
print(callable(s))  # False

def index():
    pass
print(callable(index))  # True

7.chr() 根据ASCII码转数字找字符 ord() 根据ASCII码转字符找数字

print(chr(65))  # A

print(ord('Z'))  # 90

8.complex() 将数字转化为复数。如果第一个参数为字符串,则不需要指定第二个参数

print(complex(1, 3))  # (1+3j) 数字

print(complex(111))  # (111+0j) 数字

print(complex('111'))  # (111+0j) 当做字符串处理

9.dir() 查看当前对象可以调用的名字

print(dir())  #  获得当前模块的属性列表

print(dir([])) # 查看列表的方法

def index():
    pass
print(dir(index))  # 查看函数的方法



10.divmod() 把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)


print(divmod(101, 10))  # (10, 1)
"""总数据100 每页10条  10页"""
"""总数据99  每页10条  10页"""
"""总数据101 每页10条  11页"""
num,more = divmod(233,10)
if more:
    num += 1
print('总共需要%s页'%num)

11.eval()只能识别简单的语法 exec()可以识别复杂语法。都是将字符串中的数据内容加载并执行

res1 = """
print('hello world')
"""
eval(res1)  # hello world
exec(res1)  # hello world


res = """
for i in range(10):
    print(i)
"""
# eval(res) # 复杂的无法识别
exec(res)  # 可以看到结果

12.isinstance() 来判断一个对象是否是一个已知的类型

print(isinstance(123, float))  # False

print(isinstance(123, int))  # True

print(isinstance(123, (str, int, list)))  # 是元组中的一个返回True

13.pow() 方法返回 xy(x 的 y 次方) 的值

print(pow(2, 2))  # 4

print(pow(4, 3))  # 27

14.round() 方法返回浮点数x的四舍五入值

a = 4.6
print(round(a))  # 5

b = 4.5
print(round(b))  # 4 可以看成是五舍六入

c = 8.6
print(round(c))  # 9

15.sum() 方法对序列进行求和计算

l = [11, 22, 33, 44]
print(sum(l))  # 110

推荐阅读