初识生成器python
生成器的本质就是迭代器,在python社区中,大多数时候都把迭代器和生成器是作同一个概念。app
惟一的不一样就是:函数
迭代器都是Python给你提供的已经写好的工具或者经过数据转化得来的,(好比文件句柄,iter([1,2,3])。工具
生成器是须要咱们本身用python代码构建的工具。最大的区别也就如此了。编码
生成器的构建方式3d
在 python 中有三种方式来建立生成器:code
生成器函数orm
# 函数: def func(): print(111) return 222 ret = func() print(ret) # 结果: # 111 # 222 # 生成器函数: def func(): print(111) yield 222 ret = func() print(ret) # 结果: # <generator object func at 0x102cd3d00>
将函数中的 return 换成 yield,func 就不是函数了,而是一个生成器函数。对象
因为函数中存在yield,那么这个函数就是一个生成器函数.咱们在执行这个函数的时候.就再也不是函数的执行了.而是获取这个生成器对象ip
生成器的本质就是迭代器.迭代器如何取值,生成器就如何取值。因此咱们能够直接执行next()来执行如下生成器
def func(): print("111") yield 222 gener = func() # 这个时候函数不会执⾏. ⽽是获取到⽣成器 ret = next(gener) # 这个时候函数才会执⾏ print(ret) # 而且yield会将func生产出来的数据 222 给了 ret。 结果: 111 222
而且个人生成器函数中能够写多个yield。
def func(): print("111") yield 222 print("333") yield 444 gener = func() ret = gener.__next__() print(ret) ret2 = gener.__next__() print(ret2) ret3 = gener.__next__() # 最后⼀个yield执⾏完毕. 再次__next__()程序报错 print(ret3) 结果: 111 222 333 444
当程序运行完最后一个yield,那么后面继续运行next()程序会报错,一个yield对应一个next,next超过yield数量,就会报错,与迭代器同样。
yield与return的区别:
return 通常在函数中只设置一个,他的做用是终止函数,而且给函数的执行者一个返回值。
yield 在生成器函数中能够设置多个,他并不会终止函数,next 会获取对应 yield 生成的元素。
举例:
咱们来看一下这个需求:老男孩向楼下卖包子的老板订购了10000个包子.包子铺老板很是实在,一下就所有都作出来了。
def eat(): lst = [] for i in range(1, 10001): lst.append(f'{i}号包子') return lst e = eat() print(e)
这样作没有问题,可是咱们因为学生没有那么多,只吃了2000个左右,剩下的8000个,就只能占着必定的空间,放在一边了。若是包子铺老板效率够高,我吃一个包子,你作一个包子,那么这就不会占用太多空间存储了,完美。
def gen_eat(): for i in range(1, 10001): yield f'{i}号包子' e = gen_eat() for i in range(200): print(next(e)) for i in range(300): print(next(e)) # 屡次next包子的号码是按照顺序记录的。
这二者的区别:
第一种:直接把包子全作出来,占用内存。
第二种:吃一个,包一个,很是节省内存,并且还能够保留上次的位置。
yield from
在python3中提供一种能够直接把可迭代对象中的每个数据做为生成器的结果进行返回。
# 对比yield 与 yield from def func(): lst = ['卫龙','老冰棍','北冰洋','牛羊配'] yield lst g = func() print(g) print(next(g)) # 只是返回一个列表 def func(): lst = ['卫龙','老冰棍','北冰洋','牛羊配'] yield from lst g = func() print(g) # 他会将这个可迭代对象(列表)的每一个元素当成迭代器的每一个结果进行返回。 print(next(g)) print(next(g)) print(next(g)) print(next(g)) ''' yield from ['卫龙','老冰棍','北冰洋','牛羊配'] 等同于: yield '卫龙' yield '老冰棍' yield '北冰洋' yield '牛羊配' '''
有个小坑,yield from 是将列表中的每个元素返回,因此 若是写两个yield from 并不会产生交替的效果。
def func(): lst1 = ['卫龙','老冰棍','北冰洋','牛羊配'] lst2 = ['馒头','花卷','豆包','大饼'] yield from lst1 yield from lst2 g = func() for i in g: print(i) # 卫龙 # 老冰棍 # 北冰洋 # 牛羊配 # 馒头 # 花卷 # 豆包 # 大饼
列表推导式
列表推导式分为两种模式:
循环模式
将10之内全部整数的平方写入列表。
ls = [i**2 for i in range(1, 11)] print(ls)
100之内全部的偶数写入列表。
ls = [i for i in range(2, 101, 2)] print(ls)
从python1期到python100期写入列表lst。
ls = [f'python{i}期' for i in range(1, 101)] print(ls)
上面那个格式化输出的变量f'python{i}期',就是加工的变量。
上面作的那三个就是循环模式,比较简单。
筛选模式
将这个列表中大于3的元素留下来。
l1 = [4, 3, 2, 6, 5, 5, 7, 8] ls = [i for i in l1 if i > 3] print(ls) # [4, 6, 5, 5, 7, 8]
作几道题:
三十之内能够被三整除的数。
ls = [i for i in range(1, 31) if i % 3 == 0] print(ls) # [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母。
l1 = ['Dylan', 'xiaobai', 'ab', '33434', '1b'] ls = [i.upper() for i in l1 if len(i) > 3] print(ls) # ['DYLAN', 'XIAOBAI', '33434']
找到嵌套列表中名字含有两个‘e’的全部名字(有难度)
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] ls = [name.upper() for i in names for name in i if name.count('e') == 2] print(ls) # ['JEFFERSON', 'WESLEY', 'STEVEN', 'JENNIFER']
生成器表达式
生成器表达式和列表推导式的语法上如出一辙,只是把[]换成()就好了。好比将十之内全部数的平方放到一个生成器表达式中。
gen = (i**2 for i in range(10)) print(gen) # 结果: <generator object <genexpr> at 0x0000026046CAEBF8>
生成器表达式也能够进行筛选
# 获取1-100内能被3整除的数 gen = (i for i in range(1,100) if i % 3 == 0) for num in gen: print(num)
生成器表达式和列表推导式的区别:
列表推导式比较耗内存,全部数据一次性加载到内存。而生成器表达式遵循迭代器协议,逐个产生元素。
获得的值不同,列表推导式获得的是一个列表.生成器表达式获取的是一个生成器。
列表推导式一目了然,生成器表达式只是一个内存地址。
不管是生成器表达式,仍是列表推导式,他只是Python给你提供了一个相对简单的构造方式,由于使用推导式很是简单,因此大多数都会为之着迷,这个必定要慎重,推导式只能构建相对复杂的而且有规律的对象,对于没有什么规律,并且嵌套层数比较多(for循环超过三层)这样就不建议你们用推导式构建。
生成器的惰性机制: 生成器只有在访问的时候才取值,说白了.你找他要才给你值.不找他要.他是不会执行的.
其它相关推导式(了解)
字典推导式
lst1 = ['jay','jj','meet'] lst2 = ['周杰伦','林俊杰','郭宝元'] dic = {lst1[i]:lst2[i] for i in range(len(lst1))} print(dic)
集合推导式
集合推导式能够帮咱们直接生成一个集合,集合的特色;无序,不重复 因此集合推导式自带去重功能
s = {abs(i) for i in lst} print(s)
本节咱们讲内置函数。 首先来讲,函数就是以功能为导向,一个函数封装一个功能,那么Python将一些经常使用的功能(好比len)给咱们封装成了一个一个的函数,供咱们使用,他们不只效率高(底层都是用C语言写的),并且是拿来即用,避免重复早轮子,那么这些函数就称为内置函数,到目前为止python给咱们提供的内置函数一共是68个,因为时间关系以及考虑这些函数的不一样重要性咱们会挑经常使用的重要的内置函数去讲,就是下面红色黄色背景的内置函数,剩下的内置函数大家参照着个人博客本身课下练习一下便可。
因为咱们这没有表格的功能,我把这些内置函数进行分类:
黄色一带而过:all() any() bytes() callable() chr() complex() divmod() eval() exec() format() frozenset() globals() hash() help() id() input() int() iter() locals() next() oct() ord() pow() repr() round()
红色重点讲解:abs() enumerate() filter() map() max() min() open() range() print() len() list() dict() str() float() reversed() set() sorted() sum() tuple() type() zip() dir()
蓝色将来会讲: classmethod() delattr() getattr() hasattr() issubclass() isinstance() object() property() setattr() staticmethod() super()
上面的黄色,红色的内置函数是在这两天讲完的(讲过的就不讲了),蓝色的讲完面向对象会给你们补充,剩余还有一些课上就不讲了,课下练习一下就能够。
eval:执行字符串类型的代码,并返回最终结果。
eval('2 + 2') # 4 n=81 eval("n + 4") # 85 eval('print(666)') # 666
exec:执行字符串类型的代码。
s = ''' for i in [1,2,3]: print(i) ''' exec(s)
hash:获取一个对象(可哈希对象:int,str,Bool,tuple)的哈希值。
print(hash(12322)) print(hash('123')) print(hash('arg')) print(hash('alex')) print(hash(True)) print(hash(False)) print(hash((1,2,3))) ''' -2996001552409009098 -4637515981888139739 1 2528502973977326415 '''
help:函数用于查看函数或模块用途的详细说明。
print(help(list)) print(help(str.split))
callable:函数用于检查一个对象是不是可调用的。若是返回True,object仍然可能调用失败;但若是返回False,调用对象ojbect绝对不会成功。
name = 'alex' def func(): pass print(callable(name)) # False print(callable(func)) # True
int:函数用于将一个字符串或数字转换为整型。
print(int()) # 0 print(int('12')) # 12 print(int(3.6)) # 3 print(int('0100',base=2)) # 将2进制的 0100 转化成十进制。结果为 4
float:函数用于将整数和字符串转换成浮点数。
complex:函数用于建立一个值为 real + imag * j 的复数或者转化一个字符串或数为复数。若是第一个参数为字符串,则不须要指定第二个参数。。
print(float(3)) # 3.0 print(complex(1,2)) # (1+2j)
bin:将十进制转换成二进制并返回。
oct:将十进制转化成八进制字符串并返回。
hex:将十进制转化成十六进制字符串并返回。
print(bin(10),type(bin(10))) # 0b1010 <class 'str'> print(oct(10),type(oct(10))) # 0o12 <class 'str'> print(hex(10),type(hex(10))) # 0xa <class 'str'>
divmod:计算除数与被除数的结果,返回一个包含商和余数的元组(a // b, a % b)。
round:保留浮点数的小数位数,默认保留整数。
pow:求x**y
次幂。(三个参数为x**y
的结果对z取余)
print(divmod(7,2)) # (3, 1) print(round(7/3,2)) # 2.33 print(round(7/3)) # 2 print(round(3.32567,3)) # 3.326 print(pow(2,3)) # 两个参数为2**3次幂 print(pow(2,3,3)) # 三个参数为2**3次幂,对3取余。
bytes:用于不一样编码之间的转化。
# s = '你好' # bs = s.encode('utf-8') # print(bs) # s1 = bs.decode('utf-8') # print(s1) # bs = bytes(s,encoding='utf-8') # print(bs) # b = '你好'.encode('gbk') # b1 = b.decode('gbk') # print(b1.encode('utf-8'))
ord:输入字符找该字符编码的位置
chr:输入位置数字找出其对应的字符
# ord 输入字符找该字符编码的位置 # print(ord('a')) # print(ord('中')) # chr 输入位置数字找出其对应的字符 # print(chr(97)) # print(chr(20013))
repr:返回一个对象的string形式(原形毕露)。
# %r 原封不动的写出来 # name = 'taibai' # print('我叫%r'%name) # repr 原形毕露 print(repr('{"name":"alex"}')) print('{"name":"alex"}')
all:可迭代对象中,全都是True才是True
any:可迭代对象中,有一个True 就是True
# all 可迭代对象中,全都是True才是True # any 可迭代对象中,有一个True 就是True # print(all([1,2,True,0])) # print(any([1,'',0]))