#魔法方法, 属性 和 迭代器
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 = 'Squ
linuxjishu/13830.html target=_blank class=infotextkey>awk!'
... 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) 返回一个类的超类的绑定实例