Python 构造函数:


class FooBar:
    def __init__(self):
        self.somevar = 42

运行结果


>>> f = FooBar()


>>> f.somevar


42



接受参数的构造函数:


class FooBar:
    def __init__(self, value=42):
        self.somevar = value

结果:


>>> f = FooBar('This is a constructor argument')
>>> f.somevar




析构函数


__del__

由于Python有carbage colletion的机制,所以,建议尽量不要使用析构函数

调用超类super的构造函数



由于在子类中,超类的构造函数被重载,所以超类构造函数里面定义的变量,在子类中都不会声明,要避免这种情况,需要在子类的构造函数中调用超类的构造函数,这里有两种方法。



第一种,直接利用超类名来构造。



class SongBird(Bird):
    def __init__(self):
        Bird.__init__(self)
        self.sound = 'Squawk!'
    def sing(self):
        print self.sound



第二种方法,利用super函数。




__metaclass__ = type # super only works with new-style classes
class Bird:
    def __init__(self):
        self.hungry = True
    def eat(self):
        if self.hungry:
        print 'Aaaah...'
        self.hungry = False
        else:
        print 'No, thanks!'
class SongBird(Bird):
    def __init__(self):
        super(SongBird, self).__init__()
        self.sound = 'Squawk!'

        def sing(self):
                print self.sound



最好使用super函数的方法,这有很多好处,特别是在有多个超类的时候。







Basic Sequence and Mapping protocol



Sequence 和 Mapping是最基本的数据的集合。要实现他们的行为,如果是immutable的需要完成两个protocol,如果是mutable的话需要完成4个protocol

__len__(self): 用来返回集合中的元素个数,如果是Sequence的话,返回值则是Sequence里面的元素的个数,如果是Mapping的话,返回的值是key-value对的数目。如果__len__返回0,那么在需要布尔值的情况会转换为false。.
__getitem__(self, key): 用来返回key所对应的值。入股是Sequence,这个key就是一个小于元素个数的整数。如果是mapping那么就可以是任意一个值。

__setitem__(self, key, value): 将value存储在key所对应的位置。
__delitem__(self, key): 当使用del语句时,用来删除key对对应的元素。

exstra:

在一个Sequence中如果这个整数是一个负数,那么则相当与从底端开始x[-n] 相当与x[len(x)-n]

当键值不匹配的时候抛出一个TypeError异常

当索引的类型正确,但是越界了,则抛出一个IndexError

下面是一个无穷数列的代码:

def checkIndex(key):
    """
    Is the given key an acceptable index?
    To be acceptable, the key should be a non-negative integer. If it
    is not an integer, a TypeError is raised; if it is negative, an
    IndexError is raised (since the sequence is of infinite length).
    """
    if not isinstance(key, (int, long)): raise TypeError
    if key<0: raise IndexError
class ArithmeticSequence:
   def __init__(self, start=0, step=1):
      """
      Initialize the arithmetic sequence.
      start - the first value in the sequence
      step - the difference between two adjacent values
      changed - a dictionary of values that have been modified by
      the user
      """
      self.start = start
      # Store the start value
      self.step = step
      # Store the step value
      self.changed = {}
      # No items have been modified
   def __getitem__(self, key):
      """
      Get an item from the arithmetic sequence.
      """
      checkIndex(key)
      try: return self.changed[key]           # Modified?
      except KeyError:                             # otherwise...
         return self.start + key*self.step    # ...calculate the value


    def __setitem__(self, key, value):
        """
        Change an item in the arithmetic sequence.
        """
        checkIndex(key)
        self.changed[key] = value             # Store the changed value

结果:



>>> s = ArithmeticSequence(1, 2)
>>>s[4]
9
>>>s[4] = 2

>>>s[4]
2
>>>s[5]
11





类中的属性,用访问器(accessor)来访问的话,可以通过property函数来使得他与普通的属性访问方法相同,比如:


__metaclass__ = type
class Rectangle:
    def __init__(self):
        self.width = 0
        self.height = 0
    def setSize(self, size):
        self.width, self.height = size
    def getSize(self):
        return self.width, self.height
    size = property(getSize, setSize)



运行结果:

>>> r = Rectangle()
>>> r.width = 10
>>> r.height = 5
>>> r.size
(10, 5)
>>> r.size = 150, 100
>>> r.width
150

访问起来,类似于C++中重载了 =操作符,一点要注意的是property函数第一个参数是getter,第二个是setter,还有这是new style的class。

property可以接受,0个,1个,2个,3个和四个参数,四个参数分别为fget, fset, fdel, doc,如果是0个参数,那么就不可读也不可写,如果是1个参数,那么是只读;两个参数是可读可写,三个参数是可以删除,第四个是document。

静态方法(static method)和类方法(class method)


静态方法和类方法可以直接通过类来访问,静态方法不需要参数,类方法需要一个类似与self的参数cls。定义的方法如下:



__metaclass__ = type
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)



2.4以后的版本,提供了一种新的定义方法,如下:




__metaclass__ = type
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'>


由于一些历史原因python静态方法和类方法用的不是很多,但是现在在一些特殊场合,比如工厂方法的时候,经常使用。








 迭代器(iterator)



除了List和dict以外,其他的对象也能迭代,只要实现了__iter__这个magic 方法,__iter__不不接收参数,返回一个任意实现了next方法对象的迭代器。next()函数用来返回迭代器的“下一个值“,如果下一个值不返回任何的东西的话,需要抛出一个StopIteration的异常。

在python3.0中迭代器协议发生了改变, 迭代的对象需要实现__next__函数,而不是next,next()是一个新的内嵌函数比如next(it)等价与之前版本的it.next().

下面是一个无穷队列Fibolacci数列:

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):
        return self



内嵌的iter函数,可以将可迭代的对象转化为迭代器

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

也可以从迭代器来生成一个序列:


lass TestIterator:

    value = 0
    def next(self):
        self.value += 1
        if self.value > 10: raise StopIteration
        return self.value
    def __iter__(self):
        return self

运行结果:


>>> ti = TestIterator()
>>> list(ti)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


生产器(generator)


生产器是一种特殊的迭代器,它的定义类似于函数的定义,可以看看如下的例子,下面的代码是一个生产器,把一个多维数组平滑输出,既将一个数组的数组里面的数据按顺序输出成一列



nested = [[1, 2], [3, 4], [5]]

def flatten(nested):
    for sublist in nested:
        for element in sublist:
            yield element



你可以这样使用生产器




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



也可以这样使用

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


在2.4以后的版本,提供了一种新的语法,就是生产器表达式(generator comprehension or generator expression),它类似与List conprehension,但是它不是生成一个list而是返回一个生产器,这样的话,就可以方便你一步一步的处理



>>> g = ((i+2)**2 for i in range(2,27))
>>> g.next()



16

生产器还有一个优点,就是你如果在函数调用中使用生产器,那么不需要多余的括号,如下

sum(i**2 for i in range(10))





递归生产器


上面的例子只能flatten两层的list,如果是一个多层次混合的话,就需要递归了:


def flatten(nested):
    try:
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except TypeError:
        yield nested

结果:


>>> list(flatten(['foo', ['bar', ['baz']]]))
['foo', 'bar', 'baz']




如果没有yield的话,可以模拟生产器,代码如下:

def flatten(nested):
    result = []
    try:
    # Don't iterate over string-like objects:
        try: nested + ''
        except TypeError: pass
        else: raise TypeError
        for sublist in nested:
            for element in flatten(sublist):
                result.append(element)
   except TypeError:
        result.append(nested)
    return result