标签:
1.1 如果一个方法在B类的一个实例中被调用(或一个属性被访问),但在B类中没有找到该方法,那么会去它的超类A里面找。
1 class A: 2 ... def hello(self): 3 ... print "Hello, I‘m A." 4 ... 5 >>> class B(A): 6 ... pass 7 ... 8 >>> a = A() 9 >>> b = B() 10 >>> a.hello() 11 Hello, I‘m A. 12 >>> b.hello() 13 Hello, I‘m A.
1.2 在子类中增加功能的最基本方式是增加方法,也可以重写一些超类的方法来自定义继承的行为
1 >>>class A: 2 3 def hello(self): 4 5 print "Hello,I‘m A." 6 7 >>> class B(A): 8 9 def hello(self): 10 11 print "Hello,I‘m B." 12 13 >>> a=A() 14 15 >>> b=B() 16 17 >>> a.hello() 18 19 Hello,I‘m A. 20 21 >>> b.hello() 22 23 Hello,I‘m B.
1.3 如果一个类的构造方法被重写,那么就需要调用超类的构造方法,否则对象可能不能被正确地初始化。
1 >>> class Bird: 2 ... def __init__(self): 3 ... self.hungry = True 4 ... def eat(self): 5 ... if self.hungry: 6 ... print ‘Aaaah...‘ 7 ... self.hungry = False 8 ... else: 9 ... print ‘No, thanks!‘ 10 ... 11 >>> b = Bird() 12 >>> b.eat() 13 Aaaah... 14 >>> b.eat() 15 No, thanks! 16 >>> class SongBird(Bird): 17 ... def __init__(self): 18 ... self.sound = ‘Squawk!‘ 19 ... def sing(self): 20 ... print self.sound 21 ... 22 >>> sb = SongBird() 23 >>> sb.sing() 24 Squawk! 25 >>> sb.eat() 26 Traceback (most recent call last): 27 File "<stdin>", line 1, in <module> 28 File "<stdin>", line 5, in eat 29 AttributeError: ‘SongBird‘ object has no attribute ‘hungry‘
原因:在SongBird中,构造方法被重写,但新的构造方法没有任何关于初始化hungry特性的代码。为了达到预期效果,SongBird的构造方法必须调用其超类Bird的构造方法来确保基本的初始化。有两种方法可以达到这个目的:
1). 调用超类方法的未绑定版本;
2). 使用super函数;
1.3.1 调用未绑定的超类构造方法
1 >>> class SongBird(Bird): 2 ... def __init__(self): 3 ... Bird.__init__(self) 4 ... self.sound=‘Squark!‘ 5 ... def sing(self): 6 ... print self.sound 7 ... 8 >>> sb = SongBird() 9 >>> sb.sing() 10 Squark! 11 >>> sb.eat() 12 Aaaah... 13 >>> sb.eat() 14 No, thanks!
这样做的缺点是,当一个子类的父类发生变化时(如类B的父类由A变为C时),必须遍历整个类定义,把所有的通过非绑定的方法的类名全部替换过来
1 class A: 2 def __init__(self): 3 print "enter A" 4 print "leave A" 5 class B(A): 6 def __init__(self): 7 print "enter B" 8 A.__init__(self) 9 print "leave B" 10 >>> b = B() 11 enter B 12 enter A 13 leave A 14 leave B 15 16 17 #类B的父类由A变为C,需要修改多处代码 18 class B(C): # A --> C 19 def __init__(self): 20 print "enter B" 21 C.__init__(self) # A --> C 22 print "leave B"
1.3.2 使用super函数
1). super并不是一个函数,是一个类名,形如super(B, self)事实上调用了super类的初始化函数,产生了一个super对象;
2). super类的初始化函数并没有做什么特殊的操作,只是简单记录了类类型和具体实例;
3). super(B,
self).func的调用并不是用于调用当前类的父类的func函数;
4).
Python的多继承类是通过mro的方式来保证各个父类的函数被逐一调用,而且保证每个父类函数 只调用一次(如果每个类都使用super);
5). 混用super类和非绑定的函数是一个危险行为,这可能导致应该调用的父类函数没有调用或者一个父类函数被调用多次。
尝试执行同样的代码,结果一致,但修改的代码只有一处,把代码的维护量降到最低,是一个不错的用法。因此在我们的开发过程中,super关键字被大量使用.
1 class A(object): # A must be new-style class 2 def __init__(self): 3 print "enter A" 4 print "leave A" 5 class B(C): # A --> C 6 def __init__(self): 7 print "enter B" 8 super(B, self).__init__() 9 print "leave B"
1 #conding = utf-8 2 __metaclass__ = type # super() only works in new style classes 3 class Bird: 4 def __init__(self): 5 self.hungry = True 6 def eat(self): 7 if self.hungry: 8 print ‘Aaaah...‘ 9 self.hungry = False 10 else: 11 print ‘No, thanks!‘ 12 13 class SongBird(Bird): 14 def __init__(self): 15 super(SongBird, self).__init__() # 在Python 3.0 中, super函数可以不用任何参数进行调用, 功能依然具有"魔力" 16 self.sound = ‘Squark!‘ 17 def sing(self): 18 print self.sound 19 20 sb = SongBird() 21 sb.sing() 22 sb.eat() 23 sb.eat() 24 25 #python tt.py 26 #Squark! 27 #Aaaah... 28 #No, thanks!
2.1 基本的序列和映射规则
序列和映射是对象的集合。为了实现它们基本的行为(规则),如果对象是不可变的,那么就需要使用两个魔法方法,如果是可变的,则需要使用4个。
1) __len__(self):这个方法应该返回集合中所含项目的数量。对于序列来说,这是元素的个数;对于映射来说,是键值对的数量。如果__len__返回0(并且没有实现重写该 行为的__nozero__),对象会被当作一个布尔变量中的假值(空的列表,元组,字符串和字典也一样)进行处理。
2)__getitem__(self.key):这个方法返回与所给键对于的值。对于一个序列,键应该是一个0~n-1的整数,n是序列的长度;对于映射来说,可以使用任何种类的键。
3)__setitem__(self,key,value):这个方法应该按一定的方式存储和key相关的value,该值随后可使用__getitem__来获取。当然,只能为可以修改的对象定义这个方法。
4)__delitem__(self,key):这个方法在对一部分对象使用del语句时被调用,同时必须删除和元素相关的键。这个方法也是为可修改的对象定义的(并不是删除全部的对象, 而只删除一些需要移除的元素)。
1 #coding = utf-8 2 def checkIndex(key): 3 """ 4 所给的键时能接受的索引吗? 5 为了能被接受, 键应该是一个非负的整数. 如果它不是一个整数, 会引发TypeError; 如果它是负数, 则会引发IndexError(因为序列是无限长的) 6 """ 7 if not isinstance(key, (int, long)): raise TypeError 8 if key<0: raise IndexError 9 10 class ArithmeticSequence: 11 def __init__(self, start=0, step=1): 12 """ 13 初始化算术序列 14 起始值:序列中的第一个值 15 步长: 两个相邻值之间的差别 16 改变: 用户修改的值的字典 17 """ 18 19 self.start = start #保存开始值 20 self.step = step #保存步长值 21 self.changed = {} #没有项被修改 22 23 def __getitem__(self, key): 24 """ 25 Get an item from the arithmetic sequence. 26 """ 27 checkIndex(key) 28 try: return self.changed[key] #修改了吗? 29 except KeyError: #否则... 30 return self.start + key*self.step #...计算值 31 32 def __setitem__(self, key, value): 33 """ 34 修改算术序列中的一个项 35 """ 36 checkIndex(key) 37 self.changed[key]=value # 保存更改后的值 38 39 s = ArithmeticSequence(1, 2) 40 print s[0] 41 print s[1] 42 print s[2] 43 print s[3] 44 print s[4] 45 46 s[4]=2 47 print s[4] 48 49 print s[5]
2.2 子类化列表,字典和字符串
1 >>> class CounterList(list): 2 ... def __init__(self, *args): 3 ... super(CounterList, self).__init__(*args) 4 ... self.counter = 0 5 ... def __getitem__(self, index): 6 ... self.counter += 1 7 ... return super(CounterList, self).__getitem__(index) 8 ... 9 >>> c1 = CounterList(range(10)) 10 >>> c1 11 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 12 >>> c1.reverse() 13 >>> c1 14 [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 15 >>> del c1[3:6] 16 >>> c1 17 [9, 8, 7, 3, 2, 1, 0] 18 >>> c1.counter 19 0 20 >>> c1[4] + c1[2] 21 9 22 >>> c1.counter 23 2
标签:
原文地址:http://www.cnblogs.com/zxqstrong/p/4663746.html