面向对象的python编程
例:
>>> class Wallet:
"Where does my money go?"
walletCnt = 0
def __init__(self,balance = 0):
self.balance = balance
Wallet.walletCnt += 1
def getPaid(self,amnt):
self.balance += amnt
self.displayBalance()
def spend(self,amnt):
self.balance -= amnt
self.displayBalance()
def displayBalance(self):
print 'new balance:$%.2f'%self.balance
>>>
一、定义一个新类
class语句创建了一个名为Wallet的新类定义(它本身也是一个对象)。这个类包含一个文档字符串(使用Wallet__doc__可以访问该字符串)、已存在的所有皮夹数目以及3个方法。
对于方法,可以像常规函数一样进行声明,只是每个方法的第一个参量都为self,这是对象实例的常规Python名(它与java中的this对象或c++中的this指针具有相同的作用)。Python把self参量添加到你的列表中:当调用方法时,不需要引入它。第一个方法时特殊的构造函数或初始化方法(当你创建这个类的一个新实例时,python会调用它)。注意,它会接受初始余额来作为可选参数。另外两个方法将在皮夹当前余额的基础上进行运算。
(所有方法一定要在对象的实例上进行运算,如果是从c++中转过来的,则没有“静态方法”)。
对象可以包含两种类型的数据成员:WalletCnt,位于类的方法之外,而且是类变量,意味着类的所有实例将共享它。在一个实例中(或在类定义中)更改它的值就表明在所有地方都更改了它,所以某些皮夹可以使用WalletCnt查看已经创建的皮夹数:
>>> myWallet = Wallet()
>>> yourWallet = Wallet()
>>> print myWallet.walletCnt,yourWallet.walletCnt
4 4
另一种类型的数据成员是实例变量,它是在方法内进行定义的,而且只属于对象的当前实例,Wallet的balance成员是一个实例变量。一定要使用self参数引用它的属性,而不管它们是方法还是数据成员。
创建类的实例对象并访问
>>> w = Wallet(50.00)
>>> w.getPaid(100.00)
new balance:$150.00
>>> w.spend(25.00)
new balance:$125.00
>>> w.balance
125.0
>>>
类的实例使用词典(名为__dict__)保存属性和该实例特定的值。这样,object.attribute与object.__dict__['attribute']相同。另外,每个对象和类都包含几个其他的特殊成员:
>>> Wallet.__name__ # Class name
'Wallet'
>>> Wallet.__module__ # Module in which class was defined
'__main__'
>>> w.__class__ #Class definition
>>> w.__doc__ #Doc string
'Where does my money go?'
>>>
有关访问属性的更多信息
任何时候都可以添加,删除或修改类的属性和对象
>>> w.owner = 'Dave'
>>> w.owner
'Dave'
>>>
修改类定义会影响类的所有实例
>>> Wallet.Color = 'Blue'
>>> w.Color
'Blue'
当某个实例在没有命名的情况下修改类变量时,它只创建一个新的实例属性并修改它:
>>> w.Color = 'red'
>>> Wallet.Color
'Blue'
>>> w.Color
'red'
>>>
代替使用常规语句访问属性,可以使用getattr(obj.name[,default]),hasattr(obj.name),setattr(obj.name,value)和delattr(obj.name)函数:
>>> hasattr(w,'Color')
True
>>> getattr(w,"Color")
'red'
>>> setattr(w,'size',10)
>>> getattr(w,'size')
10
>>> delattr(w,'size')
>>> getattr(w,'size')
Traceback (most recent call last):
File "", line 1, in -toplevel-
getattr(w,'size')
AttributeError: Wallet instance has no attribute 'size'
>>>
与函数一样,方法也可以包含数据属性。
>>> class SomeClass:
def deleteFiles(self,mask):
cs.destroyFiles(mask)
deleteFiles.htmldoc = 'use with care!'
>>> hasattr(SomeClass.deleteFiles,'htmldoc')
True
>>> SomeClass.deleteFiles.htmldoc
'use with care!'
>>>
从其他类中创建新类,在新类名之后用圆括号列出父类
>>> class GetAwayVehicle:
topSpeed = 200
def engageSmokeScreen(self):
print ''
def fire(self):
print 'Bang!'
>>> class SupperMotorcycle(GetAwayVehicle):
topSpeed = 250
def engageOilSlick(self):
print "Enemies destroyed."
def fire(self):
GetAwayVehicle.fire(self)
print "kapow!"
>>> mybike = SupperMotorcycle()
>>> mybike.engageOilSlick()
Enemies destroyed.
>>> mybike.engageSmokeScreen()
>>> mybike.fire()
Bang!
kapow!
>>>
多继承
>>> class Glider:
def extendWings(self):
print 'wings ready!'
def fire(self):
print 'bombs away!'
>>> class FlyingBike(Glider,SupperMotorcycle):
pass
>>> c = FlyingBike()
>>> c.fire()
bombs away!
>>> c.extendWings()
wings ready!
>>> getattr(c,"topSpeed")
250
>>>
使用类定义对象的__bases__成员,可以得到一列基类:
>>> for base in FlyingBike.__bases__:
print base
__main__.Glider
__main__.SupperMotorcycle
>>>
创建定制的列表类
>>> import UserList,whrandom
>>> from whrandom import randint
>>> class MangleList(UserList.UserList):
def mangle(self):
data = self.data
count = len(data)
for i in range(count):
data.insert(randint(0,count - 1),data.pop())
>>> z = MangleList([1,2,3,4,5])
>>> z.mangle();print z
[4, 1, 2, 3, 5]
>>> z.mangle();print z
[5, 4, 1, 3, 2]
>>>
隐藏私有数据
采用双下划线前缀命名属性,旁观者不能查看这些属性。
Python通过内部更改包括类名的名字来保护这些成员。通过使用已损坏的名字
__className__attrName来引用属性,就能够偷偷摸摸地阻碍这个约定(进行这种操作的正当理由很少见):
>>> class FooCounter:
__secretCount = 0
def foo(self):
self.__secretCount += 1
print self.__secretCount
>>> foo = FooCounter()
>>> foo.foo()
1
>>> foo.foo()
2
>>> foo.foo()
3
>>> foo.__secretCount
Traceback (most recent call last):
File "", line 1, in -toplevel-
foo.__secretCount
AttributeError: FooCounter instance has no attribute '__secretCount'
>>> foo._FooCounter__secretCount
3
>>>
识别类成员
>>> class Tree:
pass
>>> class Oak(Tree):
pass
>>> seedling = Oak()
>>> type(seedling);type(Oak)
由于类型是实例或类,因此,所有的类定义都具有相同的类型,而且所有的实例对象都具有相同的类型。如果想查看某个对象是否是特殊类的一个实例,则可以使用isinstance(obj,class)函数
>>> isinstance(seedling,Oak)
True
>>> isinstance(seedling,Tree)
True
>>>
issubclass(class,class)进行检查,以查看一个类是否是另一个类的后继:
>>> issubclass(Oak,Tree)
True
>>> issubclass(Tree,Oak)
False
>>>
也可以使用__name__成员检索类的字符串:
>>> seedling.__class__.__name__
'Oak'
>>> seedling.__class__.__bases__[0].__name__
'Tree'
>>>
重载
>>> class Vector:
def __init__(self,a,b):
self.a = a
self.b = b
def __str__(self):
return 'Vector(%d,%d)' %(self.a,self.b)
def __add__(self,cther):
return Vector(self.a + cther.a,self.b + cther.b)
>>> v1 = Vector(2,10);v2 = Vector(5,-2)
>>> print v1,v2
Vector(2,10) Vector(5,-2)
>>> print v1 + v2
Vector(7,8)
>>>
基重载方法
注意,采用del语句,如果对象的引用计数最后变为0,Python就不会调用__del__方法。
当有人把你的对象的实例当作函数对待时,Python就会调用__call__方法。使用callable(obj)函数,用户可以测试“调用能力”.该函数试图确定这个对象是否是可调用的(callable)可以返回真,而且是错误的,如果它返回丁假,该对象确实是不可调用的)
python只在通过实例词典搜索之后调用__getattr__函数,而且基类会发生空处理,这时实现应该返回想要的属性,或者产生AttributeError异常情况。如果__setattr__需要给实例变量赋值,则应确保它赋值给实例词典而不是(self.__dict__[name] = val).以防止递归调用__setattr__。如果你自己的类包含__setattr__方法。则python总是会调用它设置成员变量值。即使实例词典已经包含要设置的变里也一样。
hash函数和cmp函数是密切相关:如果没有实现__cmp__.则也不能够实现__hash__.但没有提供__hash__,则对象的实例就不能担当词典键(如果你的对象是可变的,这就是正确的)。散列位是32仪整型数.而且被认为相等的两个实例也应该返回同一个散列值。
nonzefo函数完成了真值测试以便你的实现能够返回0或1。如果没有实现它python就会查找__len__实现,以便使用,如果还是没有找到,则对象的所有实例都会被看作“真”值。
使用__it__,__gt__和其他方法,就能够实现对rich comparisons的支持,对于这种比较,可以在不同类型的比较之间更完全地控制对象的行为。如果存在的话,python会在查找__cmp__方法之前调用其中的某些方法。
重载数字运算符
>>> class Add:
def __init__(self,val):
self.val = val
def __add__(self,obj):
print "add",obj
return self.val + obj
def __radd__(self,obj):
print "radd",obj
return self.val + obj
>>> a = Add(2)
>>> a
<__main__.Add instance at 0x00AB8AA8>
>>> a +5
add 5
7
>>> 5 + a
radd 5
7
>>>
数字的运算符方法
重载序列和词典运算符
参量to__getitem__可以是整型,也可以是切片对象。切片对象具有start,stop和step属性,所以你的类能够支持示例中给出的扩展切片。
>>> class Stepper:
def __init__(self,step):
self.step = step
def __getitem__(self,index):
if index > 5:
raise IndexError
return self.step * index
>>> s = Stepper(30)
>>> for i in s:
print i
0
30
60
90
120
150
>>>
重载按位运算符
重载类型转换
使用弱引用
通过调用weakref模块内的ref(obj[,callback]),就可以创建弱引用,其中obj是想要对它进行弱引用的对象,而callback是一个可选函数,当Python将要撤销对象(由于不存在强壮的引用)时会调用该函数;回调函数只获取一个参量,即弱引用对象。
一旦拥有了对象的弱引用.就可以通过调用弱引用,来检索引用的对象;下面的示例创建了对套接字对象的弱引用: