15. Python脚本学习笔记十五特殊方法、属性和迭代器
本篇名言:“得糊涂是一种境界,心平如境是一种修养,顺其自然是一种超脱,威武不屈是一种品格,富贵不淫是一种情操,常笑就是健康,快乐成就人生。愿你我共勉!”
在Python中,有些名称会在前后加上两个下划线,这种拼写表示名字有特殊含义。所以绝不要在自己的程序中使用这种名字。
1. __init__方法
Python 类中有默认的构造函数__init__我们可以覆盖它来试试。如下:
classFooBar:
def __init__(self):
self.somevar=42
f=FooBar()
printf.somevar
我们修改一下如下:
classFooBar:
def __init__(self,value=42):
self.somevar=value
f=FooBar("what's this?")
print f.somevar
输出如下:
what'sthis?
2. 重写方法
如果一个方法在B类的一个实例中被调用,但在B类中没有找到方法,那么就会在超类A里面找。
如下所示:
classA:
def hello(self):
print"hello ,I.m A"
classB(A):
pass
a=A()
b=B()
a.hello()
b.hello()
输出如下:
hello,I.m A
hello,I.m A
B类没有定义自己的方法hello调用的是父类的hello方法。
如果进行重写这个方法,如下:
classA:
def hello(self):
print"hello ,I.m A"
classB(A):
pass
def hello(self):
print"Hello,I'm B"
a=A()
b=B()
a.hello()
b.hello()
输出如下:
hello,I.m A
Hello,I'm B
3. 使用Super函数
我看来看下个例子如下:
classBird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print'Aaah...'
self.hungry=False
else:
print"No,thansk"
classSongBird(Bird):
def __init__(self):
self.sound='Squawk!'
def sing(self):
print self.sound
sb=SongBird()
sb.sing()
sb.eat()
运行如下:
Squawk!
Traceback(most recent call last):
AttributeError:SongBird instance has no attribute 'hungry'
没有hungry属性。
没有得到父类的属性,需要用到Super函数,处理后如下:
from_pyio import__metaclass__
__metaclass__=type
classBird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print'Aaah...'
self.hungry=False
else:
print"No,thansk"
classSongBird(Bird):
def __init__(self):
# Bird.__init__(self)
super(SongBird,self).__init__()
self.sound='Squawk!'
def sing(self):
print self.sound
sb=SongBird()
sb.sing()
sb.eat()
运行如下:
Squawk!
Aaah...
4. 成员访问
在其他语言中对象可能被要求属于某一个类,或者被要求实现某个接口,但是Python中只是简单地要求它遵循几个给定的规则。
序列和映射是对象的集合。为了实现他们基本的规则,对于可变的对象需要如下4个方法:
输入如下代码:
defcheckIndex(key):
ifnotisinstance(key,(int,long)): raiseTypeError
if key<0: raise IndexError
classArithmeticSequence:
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.changed[key]=value
s=ArithmeticSequence(1,2)
s[4]
prints[4]
s[4]=2
prints[4]
print s[5]
输出如下:
9
2
11
最开始的s[4]=start+key*step =1+4*2=9
修改后就直接返回修改后的值。
s[5]=start+key*step=1+5*2=11
当操作del s[4],时候都会报错
AttributeError:ArithmeticSequence instance has no attribute '__delitem__'
应为没有实现__del__方法。
当执行s[“four”],
if not isinstance(key,(int,long)): raiseTypeError
TypeError
s[-42]
if key<0: raise IndexError
IndexError
标准库有3个关于序列和映射规则(UserList,UserString和UserDict),可以子类化内建类型。
看如下示例,CounterList 类严重依赖于它的子类化超类(list)的行为。没有重写任何的方法。在__init__中添加了所需的初始化counter特性的行为,并在__getitem__中更新了counter特性。
classCounterList(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))
printc1
c1.reverse()
printc1
delc1[3:6]
printc1
printc1.counter
printc1[4]+c1[2]
c1.counter
执行如下:
[0, 1,2, 3, 4, 5, 6, 7, 8, 9]
[9, 8,7, 6, 5, 4, 3, 2, 1, 0]
[9, 8,7, 3, 2, 1, 0]
0
9
2
包含一个counter特性,每次列表元素被访问时,都会自增,在执行c1[4]+c1[2]后,自增两次,变为2.
5. 属性
来看个示例:
classRectangle:
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
printr.getSize()
r.setSize((150,100))
print r.width
输出如下:
(10,5)
150
通过访问器定义的特性被称为属性。
在Pyhton中有两种创建属性的机制。当前常用的是property函数。
修改成如下:
from_pyio import__metaclass__
__metaclass__=type
classRectangle:
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
printr.size
r.size = 150, 100
print r.width
输出如下:
(10,5)
150
理论上应该使用property函数而不是访问器方法。
静态方法和类成员方法分别在创建的时装入Staticmethod类型和Classmethod。类型的对象中。静态方法的定义没有self参数,且能够被类本身直接调用。
如下示例:
classMyClass:
@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()
输出如下:
Thisis a static method
Thisis a class method of __main__.MyClass
不过静态方法和类方法在Python中并不是很重要,因为大部分情况下可以使用函数或者绑定方法替换。
6. 拦截对象的特性访问
为了在访问特性的时候可以执行代码,需要使用如下4种方法。
classRectangle:
def __init__(self):
self.width=0
self.height=0
def __setattr__(self,name,value):
if name=='size':
self.width,self.height= value
print'setattr'
else:
self.__dict__[name] = value
def __getattr__(self,name):
if name=='size':
print'getattr'
return self.width,self.height
else:
raise AttributeError
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
printr.size
r.size = 150, 100
print r.width
输出如下:
(10,5)
setattr
150
7. 迭代器
方法__iter__ 是迭代器规则的基础。__iter__方法返回一个迭代器,所谓迭代器就是具有next方法的对象,这个方法在调用时不需要任何参数。
一个实现了__iter__方法的对象时可迭代的,一个实现了next方法的对象则是迭代器。
我们来实现一个迭代器:
classFibs:
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()
forf in fibs:
if f>1000:
print f
break
输出如下:
1597
此外内建函数iter可以从可迭代的对象中获得迭代器,如下:
>>> it=iter([1,2,3])
>>> it.next()
1
>>> it.next()
2
除了在迭代器和可迭代对象上进行迭代外,还能把他们转换为序列。
使用迭代器获得序列,如下代码:
classTestIterator:
value=0
def next(self):
self.value+=1
if self.value>10:raiseStopIteration
return self.value
def __iter__(self):
return self
ti=TestIterator()
print list(ti)
输出如下:
[1, 2,3, 4, 5, 6, 7, 8, 9, 10]