#魔法方法, 属性 和 迭代器 D:\>python Python 2.7.5 (default, May 15 2013, 22:43:36) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. #9.1准备工作 >>> __metaclass__=type >>> class NewStyle(object): ... pass # more_code_here ... >>> class OldStyle: ... pass # more_code_here ... #9.2 构造器(constructor) >>> 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 'This is a constructor argument' #9.2.1 重写一般方法和特殊的constructor >>> class A: ... def hello(self): ... print "Hello, I'm A." ... >>> class B(A): ... pass ... >>> a = A() >>> b = B() >>> a.hello() Hello, I'm A. >>> b.hello() Hello, I'm A. >>> >>> class B(A): ... def hello(self): ... print "Hello, I'm B" ... >>> b = B() >>> b.hello() Hello, I'm B >>> class Bird: ... def __init__(self): ... self.hungry = True ... def eat(self): ... if self.hungry: ... print 'Aaaah...' ... else: ... print 'No, thanks!' ... >>> 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! >>> class SongBird(Bird): ... def __init__(self): ... self.sound = 'Squawk!' ... def sing(self): ... print self.sound ... >>> sb = SongBird() >>> sb.sing() Squawk! >>> sb.eat() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 5, in eat AttributeError: 'SongBird' object has no attribute 'hungry' >>> #9.2 调用未绑定的超类构造器 >>> class SongBird(Bird): ... def __init__(self): ... Bird.__init__(self) ... self.sound='Squark!' ... def sing(self): ... print self.sound ... >>> sb = SongBird() >>> sb.sing() Squark! >>> sb.eat() Aaaah... >>> sb.eat() No, thanks! #9.2 使用super函数 #conding = utf-8 __metaclass__ = type # super() only works in 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__() # 在Python 3.0 中, super函数可以不用任何参数进行调用, 功能依然具有"魔力" self.sound = 'Squark!' def sing(self): print self.sound sb = SongBird() sb.sing() sb.eat() sb.eat() #python tt.py #Squark! #Aaaah... #No, thanks! #9.3 成员访问 #9.3.1 基本的序列和映射规则 #coding = utf-8 def checkIndex(key): """ 所给的键时能接受的索引吗? 为了能被接受, 键应该是一个非负的整数. 如果它不是一个整数, 会引发TypeError; 如果它是负数, 则会引发IndexError(因为序列是无限长的) """ if not isinstance(key, (int, long)): raise TypeError if key<0: raise IndexError class ArithmeticSequence: def __init__(self, start=0, step=1): """ 初始化算术序列 起始值:序列中的第一个值 步长: 两个相邻值之间的差别 改变: 用户修改的值的字典 """ self.start = start #保存开始值 self.step = step #保存步长值 self.changed = {} #没有项被修改 def __getitem__(self, key): """ Get an item from the arithmetic sequence. """ checkIndex(key) try: return self.changed[key] #修改了吗? except KeyError: #否则... return self.start + key*self.step #...计算值 def __setitem__(self, key, value): """ 修改算术序列中的一个项 """ checkIndex(key) self.changed[key]=value # 保存更改后的值 s = ArithmeticSequence(1, 2) print s[0] print s[1] print s[2] print s[3] print s[4] s[4]=2 print s[4] print s[5] #del s[4] #Traceback (most recent call last): # File "tta.py", line 51, in <module> # del s[4] #AttributeError: ArithmeticSequence instance has no attribute '__delitem__' #print s["four"] #Traceback (most recent call last): # File "tta.py", line 57, in <module> # s["four"] # File "tta.py", line 27, in __getitem__ # checkIndex(key) # File "tta.py", line 7, in checkIndex # if not isinstance(key, (int, long)): raise TypeError #TypeError #print s[-42] #Traceback (most recent call last): # File "tta.py", line 67, in <module> # print s[-42] # File "tta.py", line 27, in __getitem__ # checkIndex(key) # File "tta.py", line 8, in checkIndex # if key<0: raise IndexError #IndexError #9.3.2 对列表, 字典和字符串进行子类化 >>> class CounterList(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) ... >>> c1 = CounterList(range(10)) >>> c1 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> c1.reverse() >>> c1 [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] >>> del c1[3:6] >>> c1 [9, 8, 7, 3, 2, 1, 0] >>> c1.counter 0 >>> c1[4] + c1[2] 9 >>> c1.counter 2 #9.4更多魔力 http://www.python.org/doc/ref/specialnames.html #9.5 属性 >>> 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) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: setSize() takes exactly 2 arguments (3 given) >>> r.setSize((150, 100)) >>> r.width 150 #9.5.1 property 函数 #幸好, Python能隐藏访问器方法, 让所有特性看起来一样. 这些通过访问器定义的特性被称为属性 __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 print r.size r.size = 150, 100 print r.width #python my.py #(10, 5) #150 #9.5.2 静态方法和类成员方法 __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) MyClass.smeth() MyClass.cmeth() #python ttb.py #This is a static method #This is a class method of <class '__main__.MyClass'> __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() MyClass.cmeth() #python ttc.py #This is a static method #This is a class method of <class '__main__.MyClass'> #9.5.3 __getattr__, __setattr__, __delattr__ #__getattribute__(self, name) #__getattr__(self, name) #__setattr__(self, name) #__delattr__(self, name) class Rectangle: def __init__(self): self.width=0 self.height=0 def __setattr__(self, name, value): if name == 'size': self.width, self.height = size else: self.__dict__[name] = value def __getattr__(self, name): if name == 'size': return self.width, self.height else: raise AttributeError #9.6 迭代器 #9.6.1 迭代器规则 #__iter__方法返回一个迭代器(iterator), 所谓的迭代器就是具有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 ... 1597 #内建函数iter可以从可迭代的对象中获得迭代器 >>> it = iter([1,2,3]) >>> it.next() 1 >>> it.next() 2 #9.6.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] #9.7 生成器 #9.7.1 创建生成器 >>> nested = [[1,2],[3,4],[5]] >>> def flatten(nested): ... for sublist in nested: ... for element in sublist: ... yield element ... >>> for num in flatten(nested): ... print num ... 1 2 3 4 5 >>> list(flatten(nested)) [1, 2, 3, 4, 5] >>> g = ((i+2)**2 for i in range(2,27)) >>> g.next() 16 >>> sum(i**2 for i in range(10)) 285 >>> sum(i for i in range(1,100)) 4950 >>> sum(i for i in range(1,101)) 5050 >>> #9.7.2 递归生成器 def flatten(nested): try: for sublist in nested: for element in flatten(sublist): yield element except TypeError: yield nested print list(flatten([[[1],2],3,4,[5,[6,7]],8])) print list(flatten([[1,2],[3,4],[5]])) #python tte.py #[1, 2, 3, 4, 5, 6, 7, 8] #[1, 2, 3, 4, 5] 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 print list(flatten(['foo', ['bar', ['baz']]])) print list(flatten([[[1],2],3,4,[5,[6,7]],8])) print list(flatten([[1,2],[3,4],[5]])) #['foo', 'bar', 'baz'] #[1, 2, 3, 4, 5, 6, 7, 8] #[1, 2, 3, 4, 5] #9.7.3 通用生成器 >>> def simple_generator(): ... yield 1 ... >>> simple_generator() <generator object simple_generator at 0x00BBD418> >>> simple_generator <function simple_generator at 0x00BB2870> #9.7.4 生成器方法 def repeater(value): while True: new = (yield value) if new is not None: value = new r = repeater(42) print r.next() print r.send("Hello, world!") #42 #Hello, world! #9.7.5 模拟生成器 def flatten(nested): result = [] try: # don't iterate on strings 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 print list(flatten(['foo', ['bar', ['baz']]])) print list(flatten([[[1],2],3,4,[5,[6,7]],8])) print list(flatten([[1,2],[3,4],[5]])) #['foo', 'bar', 'baz'] #[1, 2, 3, 4, 5, 6, 7, 8] #[1, 2, 3, 4, 5] #9.8 八皇后问题 #9.8.1 生成器和回溯 #9.8.2 问题 #9.8.3 状态表示 #9.8.4 寻找冲突 #9.8.5 基本情况 #9.8.6 需要递归的情况 #9.8.7 助手函数 # coding = utf-8 #state[0]==3, 表示在第1行的皇后是在第4列 #参数nextX代表下一个皇后的水平位置(x坐标或列), nextY代表垂直位置(y坐标或行) def conflict(state, nextX): nextY = len(state) for i in range(nextY): # 如果下一个皇后和正在被考虑的当前皇后的水平距离为0(列相同)或者等于垂直距离(在一条对角线上)就返回True,否则就返回False if abs(state[i]-nextX) in (0, nextY-i): return True return False def queens(num, state): if len(state) == num - 1: for pos in range(num): if not conflict(state, pos): yield pos print list(queens(4, (1,3,0))) #[2] def queens(num, state): if len(state) == num - 1: for pos in range(num): if not conflict(state, pos): yield pos else: for pos in range(num): if not conflict(state, pos): for result in queens(num, state + (pos,)): yield(pos,) + result def queens(num=8, state=()): for pos in range(num): if not conflict(state, pos): if len(state) == num - 1: yield(pos,) else: for result in queens(num, state + (pos,)): yield (pos,) + result print list(queens(3)) #[] print list(queens(4)) #[(1, 3, 0, 2), (2, 0, 3, 1)] for solution in queens(8): print solution #[(1, 3, 0, 2), (2, 0, 3, 1)] #(0, 4, 7, 5, 2, 6, 1, 3) #(0, 5, 7, 2, 6, 3, 1, 4) #(0, 6, 3, 5, 7, 1, 4, 2) #... #(7, 3, 0, 2, 5, 1, 6, 4) print len(list(queens(8))) #92 def prettyprint(solution): def line(pos, length=len(solution)): return '. '*(pos) + 'X ' + '. '*(length-pos-1) for pos in solution: print line(pos) import random prettyprint(random.choice(list(queens(8)))) #. . X . . . . . #. . . . . X . . #. X . . . . . . #. . . . . . X . #X . . . . . . . #. . . X . . . . #. . . . . . . X #. . . . X . . . print '' prettyprint(random.choice(list(queens(4)))) #. . X . #X . . . #. . . X #. X . . #9.9 小结 #旧式类和新式类 魔法方法 构造器 重写 序列和映射 迭代器 生成器 八皇后问题 #新函数 #iter(obj) 从一个可迭代对象得到迭代器 #property(fget, fset, fdel, doc) 返回一个属性, 所有的参数都是可选的 #super(class, obj) 返回一个类的超类的绑定实例