一,切片
python中的序列的高级操作中有切片,我们之前在字符串、列表和元组中进行过介绍,这里不在说明。
二、迭代
迭代就是重复反馈过程的活动,其目的通常是为了接近并达到所需的目标或结果,每一次对过程的重复我们称作一次迭代,而每一次迭代的结果都会被用作下一次迭代的初始值。
在python中迭代是通过for ... in来完成的,当我们使用for 循环时,只需要一个合适的可迭代的队形就可完成循环。常见的可迭代的对象有:列表,字符串,集合,元组,字典等等,但是因为我们的字典和集合的顺序不一致,因此我们迭代的顺序可能与我们存储元素的顺序不一致。
from collections import Iterable
list_tmp = list()
print(isinstance(list_tmp,Iterable)) #判断list_tmp 是不是可迭代类型,是返回True 否则返回False
输出:True
二、列表生成式
列表生成式即List Comperhensions,是Python内置的非常简单却强大的可以用来创建list的生成式。比如我们生成一个列表,这个列表存放着1~10中的所有整数的平方。
print([i*i for i in range(1,11)])
在上面,八要生成的元素 x*x 放在for循环的前面这样就可以创建出列表了,如果我们给for循环的后面加上判断,就可以对for循环中的i进行筛选。比如我们可以仅需要奇数的平方
print([i*i for i in range(1,11) if i%2! = 0])
我们有for循环嵌套if语句,同样也可有for循环的嵌套。
print([i+j for i in 'ABC' for j in '123'])
练习1:
找出/var/log/目录中,所有以.log结尾的文件名或者目录名
import os
print([filename for filename in os.listdir('/var/log') if filename.endswith('.log')])
输出:
['openlmi-install.log', 'boot.log', 'vmware-vmsvc.log', 'Xorg.9.log', 'wpa_supplicant.log', 'vmware-vmusr.log', 'yum.log', 'Xorg.1.log', 'Xorg.2.log', 'Xorg.0.log']
练习2:
有一字典d = dict(a=2, b=1, c=2, B=9, A=5)
需要1.把字典的key和value值调换(不存在的key的值以None代替);
d = dict(a=2, b=1, c=2, B=9, A=5)
print({ value:key for key,value in d.items()})
输出:
{2: 'c', 1: 'b', 9: 'B', 5: 'A'}
需要2:将大小写key值合并, 统一以小写key值输出;
d = dict(a=2, b=1, c=2, B=9, A=5)
print({k.lower():d.get(k.lower(),0)+d.get(k.upper(),0) for k in d})
输出:
{'a': 7, 'b': 10, 'c': 2}
三、生成器
通过列表生成式,我们可以生成一个列表。但是有时候因为内存的限制,别标的容量有限,而且当我们创建一个包含100万个元素的列表时,不仅占用了大量的内存空间,如果我们仅仅只访问前面几个元素,那么后面的空间就白白浪费了如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的 list ,从而节省大量的空间。在 Python 中,这种一边循环一边计算的机制,称为生成器( Generator )
(一)生成器的两种实现方式
1. 列表生成式修改为生成器
#列表生成器
li = [i for i in range(100) if i%2==0]
# 生成器
g = (i for i in range(100) if i%2==0)
2. yield关键字
下面事一个生成斐波那契数列的函数。
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
这就是定义生成器的另一种方法了,如果一个函数的定义中含有yield关键字,那么这个函数就不在
是一个普通函数,而是一个生成器。
生成器和函数的执行流程不一样。函数是顺序执行的,遇到return语句或者最后一行函数语句时自
动返回。而变成生成器的函数,在每次调用next()的时候会执行,遇到yield语句返回,再次执行的时候
从上次返回的yield语句处继续执行。
生成器函数,在python解释器进行解释的时候,先对所有函数的定义进行跳过不执行,当解释器
看到生成器函数被调用时,会转到函数定义部分,如果发现这个函数如果含yield关键字的话,会跳过该
函数,不执行,直到出现该生成器的__next__()方法时,才开始运行该函数的定义代码。
(二)查看生成器内容的两种方式
在python3中 g.__next__方法(), python2.x中g.next(),使用该种方法,每次都会返回一个元素的值,
并且当所有的元素都返回后会抛出Stoplteration的错误。
例如:
在python中生成器的内置方法还有很多,比如关闭生成器的close()方法、给生成器发送一个异常(错
误),但不影响__next__()方法的throw()方法。
def test():
while True:
try:
yield 'a'
except TypeError:
print('type error')
g = test()
print(g.__next__())
g.throw(TypeError)
print(g.__next__())
输出:
a
type error
a
(三)yield关键字的理解
1. 当在函数中看到yield关键字, 那么这个函数调用的返回值是一个生成器;2. 当要执行函数时, 必须调用g.__next__();
3. 函数执行时, 直到遇到yield停止;
4. 想要继续执行, 调用g.__next__();从上一次停止的地方继续执行;
5. yeild num 执行g.__next__()是可使num作为一个返回值返回的。
6. num = yeild 时g.__next__() 仅仅只是调用生成器函数,并且执行等待在该语句处,直到进行send()
方式给num传入一个值,函数继续执行。
练习1:
生产者与消费者模型:制作包子与顾客买包子
import time
import random
def consumer(name):
print('%s准备购买包子'%(name))
while True:
kind = yield
print('%s已经购买了%s口味的包子'%(name,kind))
def producer(name):
c1 = consumer('关羽') #消费者生成器
c2 = consumer('张飞') #消费者
c2.__next__() #消费者执行
c1.__next__()
print('厨师%s正在准备制作包子'%(name))
for kind in ['酸菜','茄子','豆角']:
time.sleep(random.randint(1,4)) #随机等待1~4秒
print('%s制作了%s口味的包子'%(name,kind))
c1.send(kind)
c2.send(kind)
producer('刘备') #生产者开始生产包子
输出:
张飞准备购买包子
关羽准备购买包子
厨师刘备正在准备制作包子
刘备制作了酸菜口味的包子
关羽已经购买了酸菜口味的包子
张飞已经购买了酸菜口味的包子
刘备制作了茄子口味的包子
关羽已经购买了茄子口味的包子
张飞已经购买了茄子口味的包子
刘备制作了豆角口味的包子
关羽已经购买了豆角口味的包子
张飞已经购买了豆角口味的包子
练习1:
智障迷你聊天机器人
def chat_roboot():
res = ''
while True:
recieve = yield res
if 'age' in recieve:
res = '18'
elif 'name' in recieve:
res = '小苹果'
elif 'hello' in recieve:
res = 'hello'
else:
res = '我还太年轻,你的问题有点难'
def main():
Roboot = chat_roboot()
Roboot.__next__()
while True:
send_data = input('<<')
if send_data == 'q' or send_data == 'bye':
print('不谝了')
break
roboot_said = Roboot.send(send_data)
print('Roboot>>%s'%(roboot_said))
main()
(四)协程得的简单理解
协程是一种允许在特定位置暂停或恢复的子程序--这一点和生成器非常类似,但与生成器不同的是,协
程可以控制子程序暂停之后的代码走向,而生成器仅仅能被动的将控制权交还给调用者。