Python学习10——构造函数,迭代器

构造函数

Pythons中的构造函数命名为__init__,在对象创建后可以自动调用它们。

>>> class FooBar:
    def __init__(self):
        self.somever = 42

        
>>> f = FooBar()
>>> f.somever    #省略了之前f.init()的操作
42
>>> class FooBar:
    def __init__(self,value=42):
        self.somever = value

        
>>> f = FooBar('This is a constructor argument')    #带参数的构造函数可以直接传值
>>> f.somever
'This is a constructor argument'

 

方法重写super(SongBird,self)

>>> class Bird:
    def __init__(self):
        self.hungry = True
    def eat(self):
        if self.hungry:
            print('eat!')
            self.hungry = False
        else:
            print('No,thanks')

            
>>> b = Bird()
>>> b.eat()
eat!
>>> b.eat()
No,thanks

>>> class SongBird(Bird):
    def __init__(self):
        super().__init__()    #调用super()时,将当前类和当前实例作为参数。对其返回的对象调用方法时,调用的将是超类的方法。
        self.sound = 'Squawk'
    def sing(self):
        print(self.sound)

        
>>> sb = SongBird()
>>> sb.sing()
Squawk
>>> sb.eat()
eat!
>>> sb.eat()
No,thanks

在上面的栗子中,SongBird类继承了超类Bird,所以SongBird类可以重写超类的构造函数。在Bird中构造函数的属性是hungry,但是SongBird类重写时只定义了属性sound,

为了让初始化得以执行,SongBird的构造函数就必须调用超类Bird的构造函数,可以使用super函数来解决。

 

元素访问

创建一个无穷序列:

>>> def check_index(key):   #这是一个辅助函数
    if not isinstance(key,int):raise TypeError
    if key < 0 : raise IndexError

    
>>> class ArithmmeticSequence:
    def __init__(self,start=0,step=1):
        """
初始化这个算术序列
start--序列中的第一个值
step---两个相邻值的差
changed ---一个字典,包含用户修改后的值
"""
        self.start = start   #存储起始值
        self.step = step     #存储步长值
        self.changed = {}    #没有任何元素被修改
    def __getitem__(self,key):
        #从算术序列中获取第一个元素
        check_index(key)
        try:
            return self.changed[key]      #如果允许修改元素,就将修改的值保存在changed中。
        except KeyError:
            return self.start + key * self.step    #如果元素未修改,就计算值
    def __setitem__(self,key,value):
        #修改算术序列中的元素
        check_index(key)
        self.changed[key] = value      #存储修改后的值

        
>>> s  = ArithmmeticSequence(1,2)
>>> s[4]
9
>>> s.changed
{}
>>> s[4]=2   #修改元素
>>> s[4]
2
>>> s[5]
11
>>> s.changed
{4: 2}
>>> s['a']
Traceback (most recent call last):
  File "<pyshell#240>", line 1, in <module>
    s['a']
  File "<pyshell#226>", line 14, in __getitem__
    check_index(key)
  File "<pyshell#202>", line 2, in check_index
    if not isinstance(key,int):raise TypeError
TypeError

特殊方法:

__len__(self):返回集合包含的项数。

__getitem__(self):返回与指定键相关联的值。

__setitem__(self,key,value):存储相关联的键值。(对象可变)

__delitem__(self,key):删除与key相关联的值。(当对象可变时才需要实现这个方法)

 

继承内置类型(从list,dict和str派生)

小栗子:一个带访问计数器的列表

>>> class CounterList(list):   #继承超类list的行为
    def __iniit__(self,*args):
        supper().__init__(*args)
        self.counter = 0
    def __getitem__(self,index):
        self.counter += 1    #每访问1次,计数加1
        return super(CounterList,self).__getitem__(index)   #返回计数

    
>>> cl = CounterList(range(10))
>>> cl
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> cl.reverse()    #可以调用超类的方法
>>> cl
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> del cl[3:6]
>>> cl
[9, 8, 7, 3, 2, 1, 0]
>>> cl.counter    # CounterList类的counter属性初始值为0
0
>>> cl[4]      #访问1次列表元素,counter值加1
4
>>> cl.counter
1
>>> cl[4]+cl[2]
6
>>> cl.counter
3

 

特性(property:通过存取方法定义的属性。

>>> class Rectangle:
    def __init__(self):
        self.width = 0
        self.height = 0
    def set_size(self,size):
        self.width,self.height = size
    def get_size(self):
        return self.width,self.height

    
>>> r = Rectangle()
>>> r.width = 10
>>> r.height = 5
>>> r.get_size()
(10, 5)
>>> r.set_size((30,7))
>>> r.width
30

>>> class Rectangle:
    def __init__(self):
        self.width = 0
        self.height = 0
    def set_size(self,size):
        self.width,self.height = size
    def get_size(self):
        return self.width,self.height
    size = property(get_size,set_size)

    
>>> r = Rectangle()
>>> r.width = 30
>>> r.height = 20
>>> r.size
(30, 20)
>>> r.size = 100,150
>>> r.width
100

1.调用函数property,并将存取方法作为参数(获取方法在前,设置方法在后)创建了一个特性,然后将名称size关联到这个特性。

2.property其实是一个类。它的实例包含一些特殊方法,__get____set____delete__.

3.在调用函数property时,可以不指定参数(特性不可读和写),指定1个参数(特性是只读的),指定2个参数(特性是可读也可写的),指定3个参数(第三个参数可选,用于删除属性的方法)。

 

静态方法和类方法

创建:将方法分别包装在staticmethodclassmethod类的对象中。

静态方法无参数,直接通过类调用;类方法定义中包含cls参数(类似self),类方法也可通过对象直接调用,参数cls将自动关联到类。

>>> class MyClass:
    def smeth():
        print('this is a static method')
    smeth = staticmethod(smeth)    #静态方法
    def cmeth(cls):
        print('this is a class method of ',cls)
    cmeth = classmethod(cmeth)     #类方法

    
>>> MyClass.smeth()
this is a static method
>>> MyClass.cmeth()
this is a class method of  <class '__main__.MyClass'>

上面的小栗子替换方法有点繁琐,可以优化下:装饰器可代替手动包装,在方法或函数前面使用运算符@列出这些装饰器。(指定多个装饰器时,应用顺序与列出顺序相反)

>>> class MyClass:
    @staticmethod
    def smeth():
        print('this is a static method')
    @classmethod
    def cmeth(cls):
        print('this is a class method of ',cls)

        
>>> MyClass.smeth()
this is a static method
>>> MyClass.cmeth()
this is a class method of  <class '__main__.MyClass'>

 

迭代器

方法__iter__返回一个迭代器,它是包含方法__next__的对象,而调用这个方法时可不提供任何参数。

>>> class Fibs:
    def __init__(self):
        self.a = 0
        self.b = 1
    def __next__(self):
        self.a,self.b = self.b,self.a + self.b
        return self.a
    def __iter__(self):    #在迭代器中实现方法__iter__,这样迭代器就可直接用于for循环中
        return self

    
>>> f = Fibs()
>>> for i in f:
    if i > 1000:    #找出第一个大于1000的斐波那契数后停止运行
        print(i)
        break

    
1597

实现了方法__iter__的对象是可迭代的,而实现了方法__next__的对象是迭代器。

 

通过对可迭代对象调用内置函数iter,可获得一个迭代器。

>>> it = iter([1,2,3])
>>> next(it)
1
>>> next(it)
2

 

生成器

生成器是一种使用普通函数语法定义的迭代器。

>>> def flatten(nested):
    for sublist in nested:     #查找列表中所有的子列表
        for element in sublist:      #按顺序迭代每个子列表的元素
            yield element        #包含yield语句的函数都被称为生成器

            
>>> nested = [[1,2],[3,4],[5]]
>>> for num in flatten(nested):
    print(num)

    
1
2
3
4
5
>>> list(flatten(nested))
[1, 2, 3, 4, 5]

生成器与普通函数的差别在于,生成器不是使用return返回一个值,而是可以生成多个值,每次一个。

 

递归生成器

如果有多层嵌套列表,可以用递归实现。

>>> def fast(n):
    try:
        for sublist in n:
            for element in fast(sublist):
                yield element
    except TypeError:
        yield n

        
>>> list(fast([[1,2],3,4,[5],[6,[7]],8]))
[1, 2, 3, 4, 5, 6, 7, 8]

 

posted @ 2019-07-08 13:28  酸菜泡饭  阅读(417)  评论(0编辑  收藏  举报