python学习笔记-迭代器和类

迭代器

迭代器和可迭代对象是有区别的:

 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]

扫描二维码关注公众号,回复: 44393 查看本文章

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

 

生成器归纳:

  1. 生成器和常规函数是一样的,创建生成器的时候,会自动实现迭代器协议,以便应用到迭代背景中(如for循环)当调用这个函数的时候,函数内部的代码并不立马执行 ,这个函数只是返回一个生成器对象。当使用for进行迭代的时候, 函数内的代码才执行。
  2. 状态挂起: 在一个函数中,程序执行到yield语句的时候,程序暂停,返回yield后面表达式的值,保持状态,并跳出循环
  3. 生成器对象实现了迭代器协议(自动实现),可以调用它的__next__方法,并且在没有值可以返回的时候,产生StopIteration异常
  4. 生成器其实就是一种特殊的迭代器

在下一次调用的时候,从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__.

猜你喜欢

转载自www.cnblogs.com/kingleoric/p/8909609.html