迭代iteration
判断一个对象可迭代:
通过for循环来遍历
[root@centos01 python]# cat test.py
#!/usr/bin/env python
# coding:utf-8
s="hello"
for i in s:
print i
[root@centos01 python]# python test.py
h
e
l
l
o
[root@centos01 python]# cat test.py
#!/usr/bin/env python
# coding:utf-8
s = 1
for i in s:
print i
[root@centos01 python]# python test.py
Traceback (most recent call last):
File "test.py", line 4, in <module>
for i in s:
TypeError: 'int' object is not iterable
通过collections模块的iterable类型判断
#isinstance() 函数来判断一个对象是否是一个已知的类型
In [1]: from collections import Iterable
In [2]: isinstance('abc',Iterable)
Out[2]: True
In [3]: isinstance({"name":"vaon"},Iterable)
Out[3]: True
In [4]: isinstance([123],Iterable)
Out[4]: True
In [5]: isinstance((1,2,3),Iterable)
Out[5]: True
In [6]: isinstance(1,Iterable)
Out[6]: False
列表生成式
for循环
输出1-10之间所有整数求平方之后的结果
In [9]: [i**2 for i in range(1,11)]
Out[9]: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
for循环+if语句
输出1-10之间所有整数求平方,再跟2取余为0的结果
In [11]: [i**2 for i in range(1,11) if (i**2)%2 == 0]
Out[11]: [4, 16, 36, 64, 100]
for循环+for循环
输出'abc'和'123'的全排列
In [12]: [i+j for i in "abc" for j in "123"]
Out[12]: ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']
扩展
列出当前目录下的所有.py文件或目录
#os.listdir(".")表示列出当前目录下所有文件、目录
#i.endswith(".py")判断字符串是否以.py后缀结尾,如果以指定后缀结尾返回True,否则返回False
In [26]: [i for i in os.listdir(".") if i.endswith(".py")]
Out[26]: ['check_bool.py', 'function.py', 'test.py']
练习1
给定一个正整数,编写程序计算有多少对质数的和等于输入的这个正整数,并输出结果。输入值小于1000。如,输入为10, 程序应该输出结果为2。(共有两对质数的和为10,分别为(5,5),(3,7))
#!/usr/bin/env python
# coding:utf-8
shuru=input("输入一个正整数(<=1000):")
def zhishu(num):
for i in range(2,num):
if num%i == 0:
return False
else:
return True
p=[i for i in range(2,shuru) if zhishu(i)]
peidui=[(m,n) for m in p for n in p if m+n == shuru and m <= n]
print len(peidui)
生成器generator
背景
通过列表生成式,可以直接创建一个列表(list):
In [2]: [i for i in range(1,10)]
Out[2]: [1, 2, 3, 4, 5, 6, 7, 8, 9]
受到内存限制,列表容量肯定是有限的,例如创建一个包含 100 万个元素的列表,会占用很大的存储空间,创建过程有可能使电脑卡住。
定义
在循环的过程中不断由前一个元素推算出后一个元素,但是后续元素并不立刻生成出来。这样就不必创建完整的 list,从而节省大量的空间。在 Python 中,这种一边循环一边计算的机制,称为生成器(Generator)
使用生成器的方式
1.把一个列表生成式的[]改为()
In [3]: g=(i for i in range(1,10000000))
In [4]: g
Out[4]: <generator object <genexpr> at 0x7f9d83652dc0>
调用:
使用.next()
每调用一次显示一个元素
In [5]: g=(i for i in range(1,4))
In [6]: g.next()
Out[6]: 1
In [7]: g.next()
Out[7]: 2
In [8]: g.next()
Out[8]: 3
In [9]: g.next()
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-9-d7e53364a9a7> in <module>()
----> 1 g.next()
StopIteration:
使用for循环
In [10]: g=(i for i in range(1,4))
In [11]: for i in g:
....: print i
....:
1
2
3
2.yield用法
如果函数里面有yield关键字,那么调用这个函数的结果赋值给的变量为生成器
当生成器g调用第一个next方法时,会运行函数,直到遇到第一个yield停止
当调用第二个next方法时,会从停止的地方继续执行,直到遇到下一个yield
#!/usr/bin/env python
# coding:utf-8
def fun():
print "1." #输出"1."
yield "第一个yield" #遇到yield停止,yield后面跟的内容可以在print g.next()时显示出来
print "2."
yield "第二个yield"
print "3."
yield "第三个yield"
print "4."
yield "第四个yield"
g = fun()
print g.next()
print g.next()
print g.next()
print g.next()
执行结果:
[root@centos01 python]# python test.py
1.
第一个yield
2.
第二个yield
3.
第三个yield
4.
第四个yield
练习1:
Fibonacci(斐波纳契)数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到:1, 1, 2, 3, 5, 8, 13, 21,...,本题要求生成6个数即可
#!/usr/bin/env python
# coding:utf-8
def fib(max): #max为最终生成fib数列个数
n,a,b = 0,0,1 #n代表当前fib数列个数,a代表n-1的值,b代表n的值
while n < max:
yield b #当前第一个数列
a,b = b,a+b
n += 1
g = fib(6) #变量g就是生成器
for i in g:
print i
输出结果:
[root@centos01 python]# python test.py
1
1
2
3
5
8
3.send用法
使用send方法给生成器函数发送数据
使用send方法前,必须先调用一次next()方法
遇到下一个yield停止
#!/usr/bin/env python
# coding:utf-8
def fun():
print "start"
num1 = yield
print num1
num2 = yield
print num2
g = fun() #g是生成器
g.next() #使用send方法前,必须先调用一次next()方法
g.send(1) #将1发送给变量num1,此时num1=1
g.send(11) #将11发送给变量num1,此时num1=11
执行结果:
[root@centos01 python]# python test.py
start
1
11
Traceback (most recent call last):
File "test.py", line 13, in <module>
g.send(11) #将11发送给变量num1,此时num1=11
StopIteration
#!/usr/bin/env python
# coding:utf-8
def fun():
print "one"
num1 = yield "sss"
print num1
num2 = yield
print num2
g = fun() #g是生成器
g.next() #这里先打印"one",代码执行到num1 = yield "sss"停止,g.next()存储yield后面的内容
print g.send("hello") #从上次yield停止的地方继续执行,将"hello"发送给num1,打印出num1的值,执行到num2 = yield停止,g.send()存储yield后面的内容,由于这里为空,所以此时g.send()=None
执行结果:
[root@centos01 python]# python test.py
one
hello
None
练习1:
生产者-消费者(producer-consumer)模型,也称作有界缓冲区(bounded-buffer)问题,两个进程共享一个公共的固定大小的 缓冲区。其中一个是生产者,用于将消息放入缓冲区;另外一个是消费者,用于从缓冲区中取出消息。问题出现在当缓冲区已经满了,而此时生产者还想向其中放入 一个新的数据项的情形,其解决方法是让生产者此时进行休眠,等待消费者从缓冲区中取走了一个或者多个数据后再去唤醒它。同样地,当缓冲区已经空了,而消费 者还想去取消息,此时也可以让消费者进行休眠,等待生产者放入一个或者多个数据时再唤醒它。
#!/usr/bin/env python
# coding:utf-8
import time #调用time内置模块
food = [] #定义一个food列表,模拟包子店的所有包子
def consumer(name):
print "%s准备买包子" %(name)
while True:
baozi_name = yield
print "客户[%s]买了[%s]馅的包子" %(name,baozi_name)
food.remove(baozi_name) #当客户买了这个馅的包子就从列表中删除
def producer(name,*kind): #*kind表示使用函数中的可变参数
c1 = consumer("路飞")
c1.next()
print "%s准备制作包子..." %(name)
for i in kind:
time.sleep(3) #表示休眠3秒,模拟厨师制作包子过程
print "厨师[%s]做了[%s]馅包子" %(name,i)
food.append(i) #厨师制作了这个馅的包子就在列表中加入
c1.send(i)
producer("白胡子","牛肉","韭菜","豆沙")
练习2:
简易聊天机器人
# coding:utf-8
def chat_robot():
res = "" #由于在使用.next()时会将遇到的第一个yield后面的内容保存到.next()中,因此必须给.next()一个值,否则会报错
while True:
receive = yield res
if "hi" in receive or "hello" in receive:
res = "你好"
elif "名字" in receive or "name" in receive:
res = "我是小冰"
elif "年龄" in receive or "age" in receive:
res = "18"
elif "再见" in receive or "bye" in receive:
res = "回聊"
else:
res = "我不懂你在说什么"
Chat = chat_robot() #Chat时生成器
Chat.next() #使用send方法前,必须先调用一次next()方法
while True:
your_said = raw_input("客户>>:")
if your_said.lower() == 'q': #.lower()表示无论大写小写都转换为小写
print "robot exit..."
break
response = Chat.send(your_said)
print "小冰>>:%s" %(response)