迭代器
迭代器和可迭代对象是有区别的:
list,truple,str,dict这些都可以被迭代,但他们并不是迭代器
凡是可以for循环的,都是Iterable(可迭代对象),实现了__iter__方法
凡是可以next()的,都是Iterator(迭代器)
迭代器都是可迭代对象
迭代器有2个要素:
__iter__(): 返回迭代器对象本身。生成迭代对象时调用,返回值必须是对象自己,然后for可以循环调用next方法
next():每一次for循环都调用该方法(必须存在)
判断迭代对象
In [36]: from collections import Iterable
In [27]: L = [1,2]
In [28]: it = iter(L)
In [38]: isinstance(L,Iterable)
Out[38]: True
In [39]: isinstance(it,Iterable)
Out[39]: True
In [40]: isinstance(100,Iterable)
Out[40]: False
判断迭代器
In [41]: from collections import Iterator
In [42]: isinstance(it,Iterator)
Out[42]: True
In [43]: isinstance({'name':'zhailiang','career':'devops'},Iterator)
Out[43]: False
In [44]: isinstance((x for x in range(10)),Iterator)
Out[44]: True
迭代器:实现next方法,在没有数据可返回的时候,返回StopIteration
迭代器是一个指针,iter()是一个内置函数,可以在序列上产生迭代器
In [20]: with open('/etc/passwd') as f: # 文件对象提供迭代器协议
...: for line in f: # for循环使用迭代器协议访问文件
...: print (line)
...:
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
In [27]: L = [1,2]
In [28]: it = iter(L)
In [28]: it
Out[28]: <list_iterator at 0x7f93e0038cc0>
In [29]: next(it)
Out[29]: 1
In [30]: next(it)
Out[30]: 2
In [31]: L.append(3)
In [32]: next(it)
Out[32]: 3
In [33]: next(it)
StopIteration Traceback (most recent call last)
<ipython-input-33-bc1ab118995a> in <module>()
----> 1 next(it)
StopIteration:
查看文件每行有多少个字母:
In [4]: it = (len(x) for x in open('/app/big.txt'))
In [5]: it
Out[5]: <generator object <genexpr> at 0x7f34350fc0f8>
In [6]: type(it)
Out[6]: generator
In [7]: next(it)
Out[7]: 65
In [8]: next(it)
Out[8]: 26
迭代器是一次性消耗,使用完就结束。如果再次调用会引发StopIteration异常
可以使用用copy包中的deepcopy了将迭代器保存:
In [51]: import copy
In [49]: L
Out[49]: [1, 2, 3]
In [54]: I=iter(L)
In [55]: J=copy.deepcopy(I)
In [56]: next(I)
Out[56]: 1
In [57]: next(I)
Out[57]: 2
In [58]: next(I)
Out[58]: 3
In [59]: next(J)
Out[59]: 1
In [60]: next(J)
Out[60]: 2
生成器函数
生成器函数一定要记住三点:
1)从语法上来说,将return改成yield,使用yield语句一次返回一个结果,
在每个结果之间,挂起并继续它们的状态
2)从实现上来说,生成器自动实现了迭代器协议;
3)生成器会保留函数离开的状态,以便下次调用继续从上一次离开的地方执行
生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个
对象,而不是一次构建一个结果列表
文件也是生成器
In [34]: def gensquares(N):
...: for i in range(N):
...: yield i**2
In [35]: for item in gensquares(5):
...: print (item),
0
1
4
9
16
In [41]: def d(n):
....: for i in range(n):
....: yield i
....:
In [42]: a=d(5)
In [43]: a.next()
Out[43]: 0
In [44]: a.next()
Out[44]: 1
In [45]: a.next()
Out[45]: 2
In [46]: for i in a:print i
3
4
生成器归纳:
- 生成器和常规函数是一样的,创建生成器的时候,会自动实现迭代器协议,以便应用到迭代背景中(如for循环)当调用这个函数的时候,函数内部的代码并不立马执行 ,这个函数只是返回一个生成器对象。当使用for进行迭代的时候, 函数内的代码才执行。
- 状态挂起: 在一个函数中,程序执行到yield语句的时候,程序暂停,返回yield后面表达式的值,保持状态,并跳出循环
- 生成器对象实现了迭代器协议(自动实现),可以调用它的__next__方法,并且在没有值可以返回的时候,产生StopIteration异常
- 生成器其实就是一种特殊的迭代器
在下一次调用的时候,从yield语句暂停的地方继续执行,如此循环,直到函数执行完。
但是在python3.X中, generator(有yield关键字的函数则会被识别为generator函数)中的next变为__next__了,next是python 3.x以前版本中的方法:
In [67]: a = (x*x for x in range(10))
In [68]: a.__next__()
Out[68]: 0
In [69]: a.__next__()
Out[69]: 1
这个是斐波那契的实现:
[root@localhost python_practice]# cat yiel_1.py
#!/usr/bin/python
def fib(max):
a, b = 1, 1
while a < max:
yield a
a, b = b, a+b
for n in fib(10):
print n
tips:
a, b = b, a+b相当于
t = (b, a + b) # t是一个tuple
a = t[0]
b = t[1]
当max=10时,进入fib()生成器,执行到yield a, 返回a值以及整个生成器暂停的状态(返回一个包含当前函数所有参数的状态的iterator对象),将a值赋给n, 打印出来;因为是for语句循环,所以又回到fib(10)语句,由于是生成器,因此从上次截断的位置开始执行,b值赋给a, a+b值赋给b,又因为是while语句,则继续while循环,yield a值,循环暂停跳出返回a值及生成器状态,把a值赋给n, 打印n。如此往复,一直循环到10结束。
yield 的作用就是把一个函数变成一个 generator
下次迭代时,代码从 yield a 的下一条语句继续执行
整个过程如下:
[root@localhost python_practice]# python yiel_1.py
1
1
2
3
5
8
In [69]: f = fib(10)
In [70]: print('fib(10):', f)
fib(10): <generator object fib at 0x7fad25442f68>
利用固定长度的缓冲区来不断读取文件内容:
def readfile(fpath):
with open(fpath) as f:
while True:
buf = f.read(1024)
if buf:
yield buf
else:
return
for i in readfile("about.html"):
print i,
8 类和对象
10.1基础知识
对象可以使用普通的 属于 对象的变量存储数据。属于一个对象或类的变量被称为域。对象也可以使用 属于 类的函数来具有功能。这样的函数被称为类的方法。这些术语帮助我们把它们与孤立的函数和变量区分开来。域和方法可以合称为类的属性。
域有两种类型——属于每个实例/类的对象或属于类本身。它们分别被称为实例变量和类变量。
类使用class关键字创建。类的域和方法被列在一个缩进块中。
创建过程:
1. 实例创建——填充实例属性
2. 行为方法——在类方法中封装逻辑
3. 运算符重载——为打印内置操作提供行为
4. 定制行为——创建子类,使其特殊化
5. 定制构造函数——为超类添加初始化逻辑
[root@shanghai-WEB-228-102_nginx ~]# cat class.py
#!/usr/bin/python
class Person:
pass # an empty block
p=Person()
print p
[root@shanghai-WEB-228-102_nginx ~]# python class.py
<__main__.Person instance at 0x7f901261fef0>
这是内存的一个空间,存储对象的计算机内存地址也打印了出来。这个地址在不同服务器上会是不同的值值,因为Python可以在任何空位存储对象。
对象的方法:
[root@shanghai-WEB-228-102_nginx ~]# cat method.py
#!/usr/bin/python
#filename:method.py
class Person:
def sayhi(self):
name=raw_input('enter input your name:')
print 'hello %s,how are you?' % name
p=Person()
p.sayhi()
[root@shanghai-WEB-228-102_nginx ~]# python method.py
enter input your name:kingleoric
hello kingleoric,how are you?
self指的是类实例对象本身(注意:不是类本身)。
__init__
方法
__init__方法在类的一个对象被建立时,马上运行。这个方法可以用来对你的对象做一些你希望的 初始化 。注意,这个名称的开始和结尾都是双下划线。
[root@shanghai-WEB-228-102_nginx ~]# cat class_init.py
#!/usr/bin/python
#filename:class_init.py
class Person:
def __init__(self,name):
self.name=name
def sayhi(self):
print 'hello, my name is',self.name
p=Person('kingleoric')
p.sayhi()
[root@shanghai-WEB-228-102_nginx ~]# python class_init.py
hello, my name is kingleoric
类与对象的方法
现在我们来看一下类与对象的数据部分。它们只是与类和对象的名称空间 绑定 的普通变量,即这些名称只在这些类与对象的前提下有效。
有两种类型的 域 ——类的变量和对象的变量,它们根据是类还是对象拥有这个变量而区分。
类的变量 由一个类的所有对象(实例)共享使用。只有一个类变量的拷贝,所以当某个对象对类的变量做了改动的时候,这个改动会反映到所有其他的实例上。
对象的变量 由类的每个对象/实例拥有。因此每个对象有自己对这个域的一份拷贝,即它们不是共享的,在同一个类的不同实例中,虽然对象的变量有相同的名称,但是是互不相关的。
[root@shanghai-WEB-228-102_nginx ~]# vi objvar.py
#!/usr/bin/python
#filename:objvar.py
class Person:
population=0
def __init__(self,name):
self.name=name
print '(initializing %s)' %self.name
Person.population+=1
def __del__(self):
print '%s say bye.' %self.name
Person.population-=1
if Person.population==0:
print 'I am the last one'
else:
print 'there are still %d people left' %Person.population
def sayhi(self):
print 'hi,my name is %s.' %self.name
def howmany(self):
if Person.population==1:
print 'I am the only person here.'
else:
print 'we have %d persons here.' %Person.population
kingleoric=Person('kingleoric')
kingleoric.sayhi()
kingleoric.howmany()
leon=Person('leon liang')
leon.sayhi()
leon.howmany()
kingleoric.sayhi()
kingleoric.howmany()
[root@shanghai-WEB-228-102_nginx ~]# python objvar.py
(initializing kingleoric)
hi,my name is kingleoric.
I am the only person here.
(initializing leon liang)
hi,my name is leon liang.
we have 2 persons here.
hi,my name is kingleoric.
we have 2 persons here.
leon liang say bye.
there are still 1 people left
kingleoric say bye.
Exception AttributeError: "'NoneType' object has no attribute 'population'" in <bound method Person.__del__ of <__main__.Person instance at 0x7fa85969c440>> ignored
修改后为:
[root@shanghai-WEB-228-102_nginx ~]# cat objvar2.py
#!/usr/bin/env python
# Filename: objvar.py
class Person:
'''Represents a person.'''
population=0
def __init__(self,name):
'''Initializes the person's data.'''
self.name=name
print '(Initializing %s)' %self.name
#When this person is created, he/she adds to the population
Person.population+=1
def __del__(self):
'''I am dying.'''
print '%s says bye.' %self.name
Person.population-=1
if Person.population==0:
print 'I am the last one.'
else:
print 'There are still %d people left.' %Person.population
def sayHi(self):
'''Greeting by the person.
Really, that's all it does.'''
print 'Hi, my name is %s.' %self.name
def howMany(self):
'''Prints the current population.'''
if Person.population==1:
print 'I am the only person here.'
else:
print 'We have %d persons here.' %Person.population
swaroop=Person('kingleoric')
swaroop.sayHi()
swaroop.howMany()
kalam=Person('Abdul kalam')
kalam.sayHi()
kalam.howMany()
swaroop.sayHi()
swaroop.howMany()
[root@shanghai-WEB-228-102_nginx ~]# python objvar2.py
(Initializing kingleoric)
Hi, my name is kingleoric.
I am the only person here.
(Initializing Abdul kalam)
Hi, my name is Abdul kalam.
We have 2 persons here.
Hi, my name is kingleoric.
We have 2 persons here.
Abdul kalam says bye.
There are still 1 people left.
kingleoric says bye.
I am the last one.
解析:
__init__
方法用一个名字来初始化Person
实例。在这个方法中,我们让population
增加1
,这是因为我们增加了一个人。同样可以发现,self.name
的值根据每个对象指定,这表明了它作为对象的变量的本质。
在类里调用其他方法:
def get_avg(self):
return self.get_score() / 3
整个代码为:
#!usr/bin/python
class Student:
def __init__(self, name, chinese=0, english=0, math=0):
self.name = name
self.english = english
self.math = math
self.chinese = chinese
def get_name(self):
return self.name
def get_score(self):
return self.chinese + self.english + self.math
def get_avg(self):
return self.get_score() / 3
if __name__ == '__main__':
bob = Student('bob', 100, 85, 96)
print bob.get_name(), bob.get_score(), bob.get_avg()
结果
/usr/local/bin/python2.7 /root/PycharmProjects/spider/student_class.py
bob 281 93
__init__和__new__
__new__()是创建类实例对象,__init__是在类实例创建之后调用。
利用这个方法和类的属性的特点可以实现设计模式的单例模式。单例模式是指创建唯一对象,单例模式设计的类只能实例
1.__new__是一个静态方法,而__init__是一个实例方法.
2.__new__方法会返回一个创建的实例,而__init__什么都不返回.
3.只有在__new__返回一个cls的实例时后面的__init__才能被调用.
4.当创建一个新实例时调用__new__,初始化一个实例时用__init__.