第9章 魔法方法、属性和迭代器
9.1 准备工作
class NewStyle(Object): more_code_here class OldStyle: more_code_here
9.2 构造方法
>>> class FooBar: ... def __init__(self,value=42): ... self.somevar=value >>> f=FooBar() >>> f.somevar 42
__del__ 方法,析构函数,它在对象要被垃圾回收之前调用,但是调用的具体时间不可知的
9.2.1 重写一般方法和特殊的构造方法
>>> class A: ... def hello(self): ... print "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...' self.hungry=False else: print 'No,thanks'
class SongBird(Bird): def __init__(self): self.sound='Squawk!' def sing(self): print self.sound
b=Bird() b.eat() b.eat() sb=SongBird() sb.sing() sb.eat() #AttributeError: SongBird instance has no attribute 'hungry'
9.2.2 调用未绑定的超类构造方法
在调用一个实例方法时,该方法的self参数会被自动绑定到实例上,如果直接调用类的方法,那么就没有实例被绑定
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):
Bird.__init__(self)
self.sound='Squawk!'
def sing(self):
print self.sound
b=Bird()
b.eat()
b.eat()
sb=SongBird()
sb.sing()
sb.eat() #AttributeError: SongBird instance has no attribute 'hungry'
sb.eat()
9.2.3 使用super函数
#__metaclass__=type #新类
class Bird(object):
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__()
self.sound='Squawk!'
def sing(self):
print self.sound
b=Bird()
b.eat()
b.eat()
sb=SongBird()
sb.sing()
sb.eat() #AttributeError: SongBird instance has no attribute 'hungry'
sb.eat()
9.3 成员访问
9.3.1 基本的序列和映射规则
__len__(self)
__getitem__(self,key)
__setitem__(self,key,value)
__delitem__(self,key)
>>> class Students(object):
... def __init__(self, *args):
... self.names = args
... def __len__(self):
... return len(self.names)
...
>>> ss = Students('Bob', 'Alice', 'Tim')
>>> print len(ss)
3
>>> class testsetandget:
... kk = {};
... def __getitem__(self, key):
... return self.kk[key];
... def __setitem__(self, key, value):
... self.kk[key] = value;
... def __delitem__(self, key):
>>>
>>> a=testsetandget()
>>> a['first']=1
>>> a['first']
1
>>> a.__setitem__('second',2)
>>> a.__getitem__('second')
2
>>> a['second']
2
>>> class C(object):
... 'test test'
... def __init__(self):
... self.value = {}
... self.name = 'xxx'
... def __getitem__(self, item):
... print '__getitem__', item
... return self.value[item]
... def __setitem__(self, key, value):
... print '__setitem__', key, value
... self.value[key] = value
... def __delitem__(self, key):
... print '__delitem__', key
... del self.value[key]
... def __len__(self):
... return len(self.value)
...
>>>
>>> print C.__doc__
test test
>>> c=C()
>>> print c
<__main__.C object at 0x7f7565192910>
>>> print c['k1']
__getitem__ k1
Traceback (most recent call last):
File "
File "
KeyError: 'k1'
>>> c[k1]='Hello'
Traceback (most recent call last):
File "
NameError: name 'k1' is not defined
>>> c['k1']='Hello'
__setitem__ k1 Hello
>>> c['k2']='5'
__setitem__ k2 5
>>> c['k1']
__getitem__ k1
'Hello'
>>> c['k2']
__getitem__ k2
'5'
>>> len(c)
2
>>> del c['k1']
__delitem__ k1
>>> len(c)
1
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):
self.start=start #保存开始值
self.step=step #保存步长值
self.changed={} #没有项被修改
def __getitem__(self,key):
'''
从序列中获取一个项
'''
checkIndex(key)
try:return self.changed[key] #修改了吗?
except KeyError: #否则
return self.start+key*self.step #计算值
def __setitem__(self,key,value):
'''
修改算术序列中的一个项
'''
checkIndex(key)
self.change[key]=value #保存更改后的值
s=ArithmeticSequence(1,2)
print s[4]
s[4]=2
print s[4]
9.3.2子类化列表、字典和字符串
子类化列表
class CounterList(list):#间接将Object子类化了
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))
print c1
c1.reverse()
print c1
del c1[3:6]
print c1
print c1.counter
print c1[4]+c1[2]
print c1.counter
9.4 更多的魔力
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
print r.getSize() #(10, 5)
r.setSize((150,100))
print r.getSize() #(150, 100)
9.5.1 property函数
#!/usr/bin/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 #(10, 5) r.size=150,100 print r.size # (150, 100)
9.5.2 静态方法和类成员方法
class TestClassMethod(object):
METHOD = 'method hoho'
def __init__(self):
self.name = 'leon'
def test1(self):
print 'test1'
print self
@classmethod
def test2(cls):
print cls
print 'test2'
print TestClassMethod.METHOD
print '----------------'
@staticmethod
def test3():
print TestClassMethod.METHOD
print 'test3'
test1为实例方法
test2为类方法,第一个参数为类本身
test3为静态方法,可以不接收参数
类方法和静态方法皆可以访问类的静态变量(类变量),但不能访问实例变量,test2、test3是不能访问self.name的,而test1则可以
程序运行结果:
>>> a=TestClassMethod()
>>> a.test1()
test1
<__main__.TestClassMethod object at 0x7f1cebbbff50>
>>> a.test2() #类成员方法可以直接用类的具体对象调用
test2
method hoho
----------------
>>> a.test3()
method hoho
test3
>>> TestClassMethod.test3()
method hoho
test3
class MyClass(object):
@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()
运行结果:
This is a static method
This is a class method of
9.5.3 __getattr__、setattr__和它的朋友们
>>> class A(object):
... def __init__(self):
... self.name = 'from __dicts__: zdy'
... def __getattr__(self, item):
... print "Hello world"
... if item == 'name':
... return 'from __getattr__: zdy'
... elif item == 'age':
... return 26
...
>>>
>>>
>>>
>>> a = A()
>>> print a.name
from __dicts__: zdy
>>> print a.age
Hello world
26
9.6 迭代器
9.6.1 迭代器规则
迭代器就是具有next方法,在调用next方法时,迭代器会返回它的下一个值。如果next被调用,
但是迭代器没有值可以返回,就会引发一个StopIteration异常
容器是一系列元素的集合,str、list、set、dict、file、sockets对象都可以看作是容器,容器都可以被迭代(用在for,while等语句中),因此他们被称为可迭代对象。
一个实现了__iter__方法的对象是可迭代的对象,一个实现了next方法的对象是迭代器,iter(可迭代对象)转换为迭代器
生成器是一种特殊的迭代器,它的返回值不是通过return而是用yield。
调用next方法,同时返回self对象
class Fibs(object): def __init__(self): self.a=0 self.b=1 def next(self): self.a,self.b=self.b,self.a+self.b if self.a>100:raise StopIteration return self.a def __iter__(self): return self
fibs=Fibs() for f in fibs: if f >1000: print f break >>>fibs.next() >>> fibs=Fibs() >>> list(fibs) [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
it=iter([1,2,3]) it.next() it.next() it.next() it.next() #StopIteration异常
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() print list(ti) #list会执行ti.next() #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
9.7 生成器
生成器是一种用普通的函数语法定义的迭代器
9.7.1 创建生成器
任何包含yield语句的函数成为生成器,yield每次产生一个值,函数就会被冻结
,等待被激活,函数被激活后就从停止的那点开始执行
>>> 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
9.7.2 递归生成器,处理任意层的嵌套
>>> def flatten(nested): ... try: ... for sublist in nested: ... for element in flatten(sublist): ... yield element ... except TypeError: ... yield nested ... >>> >>> list(flatten([[[1],2],3,4,[5,[6,7]],8])) [1, 2, 3, 4, 5, 6, 7, 8]
>>> list(flatten(['foo',['bar',['baz']]])) RuntimeError: maximum recursion depth exceeded
>>> 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 ... >>> >>> list(flatten(['foo',['bar',['baz']]])) ['foo', 'bar', 'baz']
9.7.3 通用生成器
生成器是由两部分组成:生成器的函数(def语句定义,包含yield部分)和生成器的迭代器(函数返回的部分)
>>> def smple_generator(): ... yield 1 ... >>> smple_generator()>>> smple_generator()
生成器的函数返回的迭代器可以像其他的迭代器那样使用
9.7.4 生成器方法
send()
next()
throw()
close()
>>> def repeater(value): ... while True: ... new=(yield value) ... if new is not None:value=new ... >>> r=repeater(42) >>> r.next() 42 >>> r.send("Hello world!") 'Hello world!'
9.7.5 模拟生成器
yied some_expression
用下面的语句替换:
result=[]
result.apped(some_expression)
return result
>>> def flatten(nested): ... result=[] ... try: ... 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 ... >>> >>> >>> list(flatten([[[1],2],3,4,[5,[6,7]],8])) [1, 2, 3, 4, 5, 6, 7, 8] >>> list(flatten(['foo',['bar',['baz']]])) ['foo', 'bar', 'baz']
9.8 八皇后的问题
9.8.1 生成器和回溯
9.6 迭代器
9.6.1 迭代器规则
9.6.2 从迭代器得到序列
9.7 生成器
9.7.1 创建生成器
9.7.2 递归生成器
9.7.3 通用生成器
9.7.4 生成器方法
9.7.5 模拟生成器
9.8 八皇后的问题
9.8.1 生成器和回溯
9.8.2 问题
9.8.3 状态表示
9.8.4 寻找冲突
9.8.5 基本情况
9.8.6 需要递归的情况
9.8.7 打包