万恶之源-生成器

1 生成器python

1.1 初识生成器app

什么是生成器?这个概念比较模糊,各类文献都有不一样的理解,可是核心基本相同。生成器的本质就是迭代器,在python社区中,大多数时候都把迭代器和生成器是作同一个概念。不是相同么?为何还要建立生成器?生成器和迭代器也有不一样,惟一的不一样就是:迭代器都是Python给你提供的已经写好的工具或者经过数据转化得来的,(好比文件句柄,iter([1,2,3])。生成器是须要咱们本身用python代码构建的工具。最大的区别也就如此了。函数

1.2 生成器的构建方式工具

在python中有三种方式来建立生成器:编码

  1. 经过生成器函数code

  2. 经过生成器推导式orm

  3. python内置函数或者模块提供(其实1,3两种本质上差很少,都是经过函数的形式生成,只不过1是本身写的生成器函数,3是python提供的生成器函数而已)对象

1.3 生成器函数ip

咱们先来研究经过生成器函数构建生成器。内存

首先,咱们先看一个很简单的函数:

复制代码
def func():

print(11)

return 22

ret = func()

print(ret)

运行结果:


11

22
复制代码
将函数中的return换成yield,这样func就不是函数了,而是一个生成器函数

def func():
print(11)
yield 22
咱们这样写没有任何的变化,这是为何呢? 咱们来看看函数名加括号获取到的是什么?

复制代码
def func():

print(11)

yield 22

ret = func()

print(ret)

运行结果:


<generator object func at 0x000001A575163888>
复制代码
运行的结果和最上面的不同,为何呢?? 因为函数中存在yield,那么这个函数就是一个生成器函数.

咱们在执行这个函数的时候.就再也不是函数的执行了.而是获取这个生成器对象,那么生成器对象如何取值呢?

以前咱们说了,生成器的本质就是迭代器.迭代器如何取值,生成器就如何取值。因此咱们能够直接执行next()来执行如下生成器

复制代码
def func():

print("111")

yield 222

gener = func() # 这个时候函数不会执⾏. ⽽是获取到⽣成器

ret = gener.next() # 这个时候函数才会执⾏

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,10000):

lst.append('包子'+str(i))

return lst

e = eat()

print(e)
复制代码
这样作没有问题,可是咱们因为学生没有那么多,只吃了2000个左右,剩下的8000个,就只能占着必定的空间,放在一边了。若是包子铺老板效率够高,我吃一个包子,你作一个包子,那么这就不会占用太多空间存储了,完美。

复制代码
def eat():

for i in range(1,10000):

yield '包子'+str(i)

e = eat()

for i in range(200):
next(e)
复制代码
这二者的区别:

第一种是直接把包子所有作出来,占用内存。

第二种是吃一个生产一个,很是的节省内存,并且还能够保留上次的位置。

复制代码
def eat():

for i in range(1,10000):

yield '包子'+str(i)

e = eat()

for i in range(200):
next(e)

for i in range(300):
next(e)

屡次next包子的号码是按照顺序记录的。

复制代码
1.4 send 方法(了解,不讲)

·接下来咱们再来认识一个新的东西,send方法

View Code
send和next()区别:

相同点:

        send 和 next()均可以让生成器对应的yield向下执行一次。

        均可以获取到yield生成的值。

    不一样点:

        第一次获取yield值只能用next不能用send(能够用send(None))。

        send能够给上一个yield置传递值。

1.4 yield from

在python3中提供一种能够直接把可迭代对象中的每个数据做为生成器的结果进行返回

View Code
有个小坑,yield from 是将列表中的每个元素返回,因此 若是写两个yield from 并不会产生交替的效果

View Code
2. 推导式

本节咱们讲列表推导式,生成器表达式以及其余推导式,我认为推导式就是构建比较有规律的列表,生成器,字典等一种简便的方式。那么他如何简便呢?看下面的例题:

2.1列表推导式

这里让学生本身作一下,首先咱们先看一下这样的代码,给出一个列表,经过循环,想列表中添加1~10:

View Code
那么按照上面的要求咱们用列表推导式写一下:

View Code
怎么样?一行搞定,上面这个代码就是列表推导式,接下来咱们将列表推导式进行一个分类:

列表推导式分为两种模式:

1.循环模式:[变量(加工的变量) for 变量 in iterable]

2.筛选模式: [变量(加工的变量) for 变量 in iterable if 条件]

固然还有多层循环的,这个咱们一会就会讲到,那么咱们先来看循环模式。

2.2 循环模式

刚才咱们看到的就是循环模式,那么有同窗会问到,什么叫' 加工的变量'? 这个也比较简单,接下来咱们作几道题:

将10之内全部整数的平方写入列表。

View Code
100之内全部的偶数写入列表.

View Code
从python1期到python100期写入列表lst

View Code
上面那个格式化输出的变量f'python{i}',就是加工的变量。

上面作的那三个就是循环模式,比较简单,接下来咱们研究筛选模式。

2.3 筛选模式

筛选模式就是在上面的基础上加上一个判断条件,将知足条件的变量留到列表中。

带着同窗们作一个题:

将这个列表中大于3的元素留下来。

View Code

经过我给你们的演示,你们作几道题:

三十之内能够被三整除的数。

View Code
过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母

View Code
找到嵌套列表中名字含有两个‘e’的全部名字(有难度)

View Code
列表推导式基本上讲完了,固然今天会作一些有关列表推导式的题,让你们更加深刻的了解。

2.4 生成器表达式

生成器表达式和列表推导式的语法上如出一辙,只是把[]换成()就好了。好比将十之内全部数的平方放到一个生成器表达式中

View Code
生成器表达式也能够进行筛选

View Code
生成器表达式和列表推导式的区别:

列表推导式比较耗内存,全部数据一次性加载到内存。而.生成器表达式遵循迭代器协议,逐个产生元素。

获得的值不同,列表推导式获得的是一个列表.生成器表达式获取的是一个生成器

列表推导式一目了然,生成器表达式只是一个内存地址。

不管是生成器表达式,仍是列表推导式,他只是Python给你提供了一个相对简单的构造方式,由于使用推导式很是简单,因此大多数都会为之着迷,这个必定要深重,推导式只能构建相对复杂的而且有规律的对象,对于没有什么规律,并且嵌套层数比较多(for循环超过三层)这样就不建议你们用推导式构建。

生成器的惰性机制: 生成器只有在访问的时候才取值,说白了.你找他要才给你值.不找他要.他是不会执行的.

2.5 其余相关的推导式(了解):

字典推导式

根据名字应该也能猜到,推到出来的是字典

View Code
集合推导式

集合推导式能够帮咱们直接生成一个集合,集合的特色;无序,不重复 因此集合推导式自带去重功能

View Code
3. 内置函数Ⅰ

本节咱们讲内置函数。 首先来讲,函数就是以功能为导向,一个函数封装一个功能,那么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:求xy次幂。(三个参数为xy的结果对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)) # 两个参数为23次幂
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]))

相关文章
相关标签/搜索