python基础学习笔记(七)

2013-05-08 00:30 by 虫师, 5728 阅读, 6 评论, 收藏编辑

魔法方法、属性

------------------------

 

准备工作

为了确保类是新型类,应该把 _metaclass_=type 入到你的模块的最开始。

class NewType(Object):
  mor_code_here
class OldType:
  mor_code_here

在这个两个类中NewType是新类,OldType是属于旧类,如果前面加上 _metaclass_=type ,那么两个类都属于新类。

 

 

构造方法

 

构造方法与其的方法不一样,当一个对象被创建会立即调用构造方法。创建一个python的构造方法很简答,只要把init方法,从简单的init方法,转换成魔法版本的_init_方法就可以了。

复制代码
class FooBar:
    def __init__(self):
        self.somevar = 42
        
>>> f =FooBar()
>>> f.somevar
42
复制代码

 

 

重写一个一般方法

 

每一个类都可能拥有一个或多个超类(父类),它们从超类那里继承行为方法。

复制代码
class A:
    def hello(self):
        print 'hello . I am A.'
class B(A):
  pass

>>> a = A()
>>> b = B()
>>> a.hello()
hello . I am A.
复制代码

因为B类没有hello方法,B类继承了A类,所以会调用A 类的hello方法。

 

在子类中增加功能功能的最基本的方式就是增加方法。但是也可以重写一些超类的方法来自定义继承的行为。如下:

复制代码
class A:
    def hello(self):
        print 'hello . I am A.'
class B(A):
    def hello(self):
        print 'hello . I am  B'

>>> b = B()
>>> b.hello()
hello . I am  B
复制代码

 

 

特殊的和构造方法

 

重写是继承机制中的一个重要内容,对一于构造方法尤其重要。看下面的例子:

复制代码
class Bird:
    def __init__(self):
        self.hungry = True
    def eat(self):
        if self.hungry:
            print 'Aaaah...'
            self.hungry = False
        else:
            print 'No, thanks!'

>>> b = Bird()
>>> b.eat()
Aaaah...
>>> b.eat()
No, thanks!
复制代码

这个类中定义了鸟有吃的能力, 当它吃过一次后再次就会不饿了,通过上面的执行结果可以清晰的看到。

那么用SongBird类来继承Bird 类,并且给它添加歌唱的方法:

复制代码
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):
                 self.sound = 'Squawk!'
         def sing(self):
                 print self.sound

>>> s = SongBird()
>>> s.sing()
Squawk!
>>> s.eat()

Traceback (most recent call last):
  File "<pyshell#26>", line 1, in <module>
    s.eat()
  File "C:/Python27/bird", line 6, in eat
    if self.hungry:
AttributeError: 'SongBird' object has no attribute 'hungry'
复制代码

异常很清楚地说明了错误:SongBird没有hungry特性。原因是这样的:在SongBird中,构造方法被重写,但新的构造方法没有任何关于初始化hungry特性的代码。为了达到预期的效果,SongBird的构造方法必须调用其超类Bird的构造方法来确保进行基本的初始化。

两种方法实现:

一 、调用未绑定的超类构造方法

复制代码
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):
                 Bird.__init__(self)
                 self.sound = 'Squawk!'
         def sing(self):
                 print self.sound


>>> s = SongBird()
>>> s.sing()
Squawk!
>>> s.eat()
Aaaah...
>>> s.eat()
No, thanks!
复制代码

在SongBird类中添加了一行代码Bird.__init__(self) 。 在调用一个实例的方法时,该方法的self参数会被自动绑定到实例上(这称为绑定方法)。但如果直接调用类的方法,那么就没有实例会被绑定。这样就可以自由地提供需要的self参数(这样的方法称为未绑定方法)。

通过将当前的实例作为self参数提供给未绑定方法,SongBird就能够使用其超类构造方法的所有实现,也就是说属性hungry能被设置。

 

二、使用super函数

复制代码
__metaclass__ = type  #表明为新式类
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

>>> s.sing()
Squawk!
>>> s.eat()
Aaaah...
>>> s.eat()
No, thanks!
复制代码

super函数只能在新式类中使用。当前类和对象可以作为super函数的参数使用,调用函数返回的对象的任何方法都是调用超类的方法,而不是当前类的方法。那就可以不同在SongBird的构造方法中使用Bird,而直接使用super(SongBird,self)

 

 

属性

 

访问器是一个简单的方法,它能够使用getHeight setHeight 之样的名字来得到或者重绑定一些特性。如果在访问给定的特性时必须要采取一些行动,那么像这样的封装状态变量就很重要。如下:

复制代码
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

>>> r = Rectangle()
>>> r.width = 10
>>> r.height = 5
>>> r.getSize()
(10, 5)
>>> r.setSize((150,100))
>>> r.width
150
复制代码

在上面的例子中,getSizesetSize方法一个名为size的假想特性的访问器方法,size是由width height构成的元组。

 

 

property 函数

 

property函数的使用很简单,如果已经编写了一个像上节的Rectangle 那样的类,那么只要增加一行代码:

复制代码
__metaclass__ = type
class Rectangle:
    def __int__(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
复制代码

在这个新版的Retangle 中,property 函数创建了一个属性,其中访问器函数被用作参数(先取值,然后是赋值),这个属性命为size 。这样一来就不再需要担心是怎么实现的了,可以用同样的方式处理widthheight size


迭代器

本节进行迭代器的讨论。只讨论一个特殊方法---- __iter__  ,这个方法是迭代器规则的基础。

 

迭代器规则

迭代的意思是重复做一些事很多次---就像在循环中做的那样。__iter__ 方法返回一个迭代器,所谓迭代器就是具有next方法的对象,在调用next方法时,迭代器会返回它的下一个值。如果next方法被调用,但迭代器没有值可以返回,就会引发一个StopIteration异常。

 

这里是一个婓波那契数例,使用迭代器如下:

复制代码
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

>>> fibs = Fibs() 
>>> for f in fibs:
      if  f  > 1000:
          print f
          break    #因为设置了break ,所以循环在这里停止。

1597
复制代码

内建函数iter可以从可迭代的对象中获得迭代器。

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

 

从迭代器得到序列

除了在迭代器和可迭代对象上进行迭代外,还能把它们转换为序列。在大部分能使用序列的情况下,能使用迭代器替换。

复制代码
class 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]
复制代码

 

 

 

生成器

 

生成器也叫 简单生成器,生成器可以帮助读者写出非常优雅的代码,当然,编写任何程序时不使用生成器也是可以的。

 

创建生成器

创建一个生成器就像创建函数一样简单。

复制代码
>>> def flatten(nested):
    for sublist in nested:
        for element in sublist:
            yield element

            
>>> nested = [[1,2],[3,4],[5]]
#使用for循环
>>> for num in flatten(nested):
    print num

    
1
2
3
4
5
#或使用list函数
>>> list(flatten(nested))
[1, 2, 3, 4, 5]
复制代码

 

递归生成器

上面创建的生成器只能处理两层嵌套,为了处理嵌套使用了两个for循环,如果要处理任意层的嵌套呢?例如,可以每层嵌套需要增加一个for循环,但不知道有几层嵌套,所以必须把解决方案变得更灵活,现在可以用递归来解决。

复制代码
>>> def fla(aa):
    try:
        for bb in aa:
            for cc in fla(bb):
                yield cc
    except TypeError:
        yield aa

>>> list(fla([[[1],2],3,4,[5,[6,7]],8]))  #注意括号层次比较多
[1, 2, 3, 4, 5, 6, 7, 8]
复制代码

  

fla被调用时有两种情况:基本情况和需要递归的情况

  在基本的情况中,函数被告知展开一个元素,这种情部下,for循环会引发一个TypeError 异常,生成会产生一个元素。

  如果展开的是一个列表,那么就需要特殊情况处理。程序必须遍历所有的子列表,并对它们调用fla

-------------------

上面的做法有一个问题:如果aa 是一个类似于字符串的对象(字符串、UnicodeUserString等),那么它就是一个序列,不会引发TypeError,但是你不想对这样的对象进行迭代。

为了处理这种情况,则必须在生成器的开始处添加一个检查语句。试着将传入的对象和一个字符串拼接,看看会不会出现TypeError,这是检查一个对象是不是类似于字符串最简单快速的方法。

复制代码
>>> def flatten(nested):
    try:
       #不要迭代类似字符串的对象
        try:nested + ''
        except TypeError: pass
        else: raise TypeError
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except TypeError:
        yield nested

        
>>> list(flatten(['foo',['bar',['baz']]]))
['foo', 'bar', 'baz']
复制代码

如果nested+’’ 引发了一个TypError ,它就会被忽略。如果没有引发TypeError,那么内层try语句就会引发一个它自己的TypeError异常。

 

 

生成器方法

生成器新属性是在开始运行后为生成器提供值的能力。表现为生成器和“外部世界”进行交流的渠道:

  * 外部作用域访问生成器的send方法,就像访问next 方法一样,只不过前者使用一个参数(发送的“消息”---任意对象)

  * 在内部则挂起生成器,yield现在作为表达式而不是语句使用,换句话说,当生成器重新运行的时候,yield方法返回一个值,也就是外部通过send方法发送的值。如果next 方法被使用,那么yield方法返回None. 

下面简单的方例子来说明这种机制:

复制代码
>>> def repeater(value):
    while True:
        new =(yield value)
        if new is not None:value = new

        
>>> r = repeater(42)
>>> r.next()
42
>>> r.send("hello, world!")
'hello, world!'
复制代码

生成器的另两个方法:

  * throw方法(使用异常类型调用,还有可选的值以及回溯对象)用于在生成器内引发一个异常(在yield表达式中)

  * close 方法(调用时不用参数)用于停止生成器。

 


迭代器

 

本节进行迭代器的讨论。只讨论一个特殊方法---- __iter__  ,这个方法是迭代器规则的基础。

 

迭代器规则

迭代的意思是重复做一些事很多次---就像在循环中做的那样。__iter__ 方法返回一个迭代器,所谓迭代器就是具有next方法的对象,在调用next方法时,迭代器会返回它的下一个值。如果next方法被调用,但迭代器没有值可以返回,就会引发一个StopIteration异常。

 

这里是一个婓波那契数例,使用迭代器如下:

复制代码
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

>>> fibs = Fibs() 
>>> for f in fibs:
      if  f  > 1000:
          print f
          break    #因为设置了break ,所以循环在这里停止。

1597
复制代码

内建函数iter可以从可迭代的对象中获得迭代器。

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

 

从迭代器得到序列

除了在迭代器和可迭代对象上进行迭代外,还能把它们转换为序列。在大部分能使用序列的情况下,能使用迭代器替换。

复制代码
class 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]
复制代码

 

 

 

生成器

 

生成器也叫 简单生成器,生成器可以帮助读者写出非常优雅的代码,当然,编写任何程序时不使用生成器也是可以的。

 

创建生成器

创建一个生成器就像创建函数一样简单。

复制代码
>>> def flatten(nested):
    for sublist in nested:
        for element in sublist:
            yield element

            
>>> nested = [[1,2],[3,4],[5]]
#使用for循环
>>> for num in flatten(nested):
    print num

    
1
2
3
4
5
#或使用list函数
>>> list(flatten(nested))
[1, 2, 3, 4, 5]
复制代码

 

递归生成器

上面创建的生成器只能处理两层嵌套,为了处理嵌套使用了两个for循环,如果要处理任意层的嵌套呢?例如,可以每层嵌套需要增加一个for循环,但不知道有几层嵌套,所以必须把解决方案变得更灵活,现在可以用递归来解决。

复制代码
>>> def fla(aa):
    try:
        for bb in aa:
            for cc in fla(bb):
                yield cc
    except TypeError:
        yield aa

>>> list(fla([[[1],2],3,4,[5,[6,7]],8]))  #注意括号层次比较多
[1, 2, 3, 4, 5, 6, 7, 8]
复制代码

  

fla被调用时有两种情况:基本情况和需要递归的情况

  在基本的情况中,函数被告知展开一个元素,这种情部下,for循环会引发一个TypeError 异常,生成会产生一个元素。

  如果展开的是一个列表,那么就需要特殊情况处理。程序必须遍历所有的子列表,并对它们调用fla

-------------------

上面的做法有一个问题:如果aa 是一个类似于字符串的对象(字符串、UnicodeUserString等),那么它就是一个序列,不会引发TypeError,但是你不想对这样的对象进行迭代。

为了处理这种情况,则必须在生成器的开始处添加一个检查语句。试着将传入的对象和一个字符串拼接,看看会不会出现TypeError,这是检查一个对象是不是类似于字符串最简单快速的方法。

复制代码
>>> def flatten(nested):
    try:
       #不要迭代类似字符串的对象
        try:nested + ''
        except TypeError: pass
        else: raise TypeError
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except TypeError:
        yield nested

        
>>> list(flatten(['foo',['bar',['baz']]]))
['foo', 'bar', 'baz']
复制代码

如果nested+’’ 引发了一个TypError ,它就会被忽略。如果没有引发TypeError,那么内层try语句就会引发一个它自己的TypeError异常。

 

 

生成器方法

生成器新属性是在开始运行后为生成器提供值的能力。表现为生成器和“外部世界”进行交流的渠道:

  * 外部作用域访问生成器的send方法,就像访问next 方法一样,只不过前者使用一个参数(发送的“消息”---任意对象)

  * 在内部则挂起生成器,yield现在作为表达式而不是语句使用,换句话说,当生成器重新运行的时候,yield方法返回一个值,也就是外部通过send方法发送的值。如果next 方法被使用,那么yield方法返回None. 

下面简单的方例子来说明这种机制:

复制代码
>>> def repeater(value):
    while True:
        new =(yield value)
        if new is not None:value = new

        
>>> r = repeater(42)
>>> r.next()
42
>>> r.send("hello, world!")
'hello, world!'
复制代码

生成器的另两个方法:

  * throw方法(使用异常类型调用,还有可选的值以及回溯对象)用于在生成器内引发一个异常(在yield表达式中)

  * close 方法(调用时不用参数)用于停止生成器。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值