n大魔力
1.构造函数
class FooBar: def __init__(self, value=42): self.somevar = value
f = FooBar('This is a constructor argument')
f.somevar --->
'This is a constructor argument'
在继承机制中调用父类的构造函数
①调用父类的类构造函数(Unbound)
class Bird: def __init__(self): self.hungry = 1 def eat(self): if self.hungry: print 'Aaaah...' self.hungry = 0 else: print 'No, thanks!'
class SongBird(Bird): def __init__(self): Bird.__init__(self) #可以使得Bird中的hungry得到初始化,否则在SongBird中调用hungry会引起异常 self.sound = 'Squawk!' def sing(self): print self.sound
②使用super函数
class SongBird(Bird): def __init__(self): super(SongBird, self).__init__() #super仅能工作于new-style类 self.sound = 'Squawk!' def sing(self): print self.sound
super函数相当智能,尤其在多重继承的情况下。
本书作者对这两种方法的一种总结:
You don’t have to understand exactly how it works internally, but you should be aware that, in most cases, it is clearly superior to calling the unbound constructors (or other methods) of your superclasses.
2.基本Sequence和Mapping协议(Protocol)
关于Protocol的说明:Where other languages might require an object to belong to a certain class, or to implement a certain interface, Python often simply requires it to follow some given protocol.
我的理解是要使得对象具有某种Builtin对象的性质所必须的一种规范。
__len__(self):
在Sequence中返回元素的个数,在Mapping中返回key-value对的个数。如果__len__返回zero(前提是未实现__nonzero__),则此对象会被当做Boolean值的false(与空 lists, tuples, strings, dictionaries相同)。
__getitem__(self, key):
返回与key相应的值,Sequence中key为0到n-1(也可以为负,后述),Mapping中为实际的key
__setitem__(self, key, value):
只能在可写对象中使用
__delitem__(self, key):
以上四个Protocols的几点说明:
①如果Sequence中的key为负数,则为从后倒数,如x[-n] = x[len(x)-n]
②如果key的类型不对,如在Sequence中使用String为key,会引发TypeError异常
③如果Sequence的key的类型对,但是越界,会引发IndexError异常
一个自定义Sequence的例子:
def checkIndex(key): 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 = {} # 注意,这里是个Dictionary,因此下面Store的一句才不会有异常 def __getitem__(self, key): 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): 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
其行为像Sequence,可以使用[]操作符,类似于C++中的Operator重载。
# ArithmeticSequence类没有定义__delitem__,所以del s[4]这样的行为会引起异常。
# s["four"]会引起TypeError
# s[-42]会引起IndexError
# 类中未定义 __len__ ,因为这是个无限长的Sequence。
## 在制作这种类似于Builtin类的时候要注意一点就是尽量遵从标准,比如这里就尽管用的是{}Dictionary,但还是用isinstance(key, (int, long))来检查key是否为整数,因为Builtin的key只能是整数。
如果从标准库继承类(这种类叫 UserList, UserString, UserDict),则不需要自己写所有的方法,只要重写自己需要的方法:
class CounterList(list): # 继承自list def __init__(self, *args): # 这里为什么加上*号? super(CounterList, self).__init__(*args) # 初始化父类 self.counter = 0 def __getitem__(self, index): self.counter += 1 return super(CounterList, self).__getitem__(index) # 调用父类
#在这里就可以直接使用list中的 append, extend, 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 ---> 0
cl[4] + cl[2] ---> 9
cl.counter ---> 2