Python基础教程之第9章 魔法方法, 属性和迭代器

#魔法方法, 属性 和 迭代器
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)		返回一个类的超类的绑定实例

你可能感兴趣的:(python)