已有 161 次阅读 2011-01-20 09:401.1. 5.2 new-style Class 及其实例从 python 2.2 起,如果一个类继承自 object 对象(或者它是任何内建类型如 list, dict, file 的子类),那它就是一个 new-style class 。在此之前,Python 不允许通过继承内建类型生成新类,也根本没有 object 这个对象。在本章5.4节的后半部分,我会介绍给大家一个方法,将 Classic class 改造成 new-style class 。
我建议每个人, 从现在开始只使用 new-style class (当然你得用 Python2.2 以上版本)。新的对象模型与传统对象模型相比, 有虽小却非常重要的优势, 可以说
接近完美。
1.2. 5.2.1 内建的 object 对象object 对象是所有内建类型及 new-style class 的祖先。 object 对象定义了一系列特殊方法(参见 5.3 节后半部分)实现所有对象的默认行为。
__new__, __init__ 方法
你可以创建 object 的直接子类,静态方法 __new__()用来创建类的实例, 实例的 __init__() 方法用来初始化自己。 默认的 __init__() 方法会忽略你传递过来的任何参数。
__delattr__, __getattribute__, __setattr__
方法
对象用这些方法来处理属性引用。
__hash__, __repr__, __str__ 方法
print(someobj) 会调用 someobj.__str__ 如果 __str__ 没有定义, 则调用 __repr__ repr(someobj) 会调用 someobj.__repr__
允许object的子类重载这些方法,或添加新方法。
1.3. 5.2.2 类方法
新的对象模型提供了两种类方法(传统对象模型没有这些方法):静态方法和类方法。只有 python2.2 及更新版本才支持类方法。需要提一下的是,在 python2.2 及更新版本中, Classic class 也实现了类方法。新的对象模型提供的诸多新特性中,有且仅有类方法这一特性被传统对象模型全功能实现。
1.3.1. 5.2.2.1静态方法
静态方法可以直接被类或类实例调用。它没有常规方法那样的特殊行为(绑定、非绑定、默认的第一个参数规则等等)。完全可以将静态方法当成一个用属性引用方式调用的普通函数来看待。任何时候定义静态方法都不是必须的(静态方法能实现的功能都可以通过定义一个普通函数来实现). 有些程序员认为,当有一堆函数仅仅为某一特定类编写时,采用类方法这种方式能够提供足够的一致性(和一定程度的 namespace 的功能)。
根据python2.4提供的新的语法,你可以象下面这样来创建一个静态方法,
1 class AClass(object):
2 @staticmethod #静态方法修饰符,表示下面的方法是一个静态方法
3 def astatic( ): print 'a static method'
4 anInstance = AClass( )
5 AClass.astatic( ) # prints: a static method
6 anInstance.astatic( ) # prints: a static method
注:staticmethod是一个内建函数, 用来将一个方法包装成静态方法, 在2.4以前版本, 要用下面的方式定义一个静态方法(不再推荐使用):
1 class AClass(object):
2 def astatic( ): print 'a static method'
3 astatic=staticmethod(astatic)
这种方法在函数定义本身比较长时经常会忘记后面这一行.
1.3.2. 5.2.2.2 类方法
一个类方法就是你可以通过类或它的实例来调用的方法,不管你是用类调用这个方法还是类的实例调用这个方法,python只会将实际的类对象做为该方法的第一个参数.记住:方法的第一个参数都是类对象而不是实例对象. 按照惯例,类方法的第一个形参被命名为 cls. 任何时候定义类方法都不是必须的(静态方法能实现的功能都可以通过定义一个普通函数来实现,只要这个函数接受一个类对象做为参数就可以了).某些程序员认为这个特性当有一堆函数仅仅为某一特定类编写时会提供使用上的一致性.
定义类方法:
Toggle line numbers
1 class ABase(object):
2 @classmethod #类方法修饰符
3 def aclassmet(cls): print 'a class method for', cls.__name__
4 class ADeriv(ABase): pass
5 bInstance = ABase( )
6 dInstance = ADeriv( )
7 ABase.aclassmet( ) # prints: a class method for ABase
8 bInstance.aclassmet( ) # prints: a class method for ABase
9 ADeriv.aclassmet( ) # prints: a class method for ADeriv
10 dInstance.aclassmet( ) # prints: a class method for ADeriv
注:classmethod是一个内建函数,用来将一个方法封装成类方法,在2.4以前版本,你只能用下面的方式定义一个类方法:
1 class AClass(object):
2 def aclassmethod(cls): print 'a class method'
3 aclassmethod=staticmethod(aclassmethod)
并没有人要求必须封装后的方法名字必须与封装前一致,但建议你总是这样做(如果你使用python2.4版本以下时). 这种方法在函数定义本身比较长时经常会忘记后面这一行.
1.4. 5.2.3 new-style class
除了拥有 Classic class 的全部特性之外, new-style class 当然还具有一些新特性.__init__特殊方法的行为与 Classic class 相比有了一些变化, 另外还新增了一个名为 __new__ 的静态方法
1.4.1. 5.2.3.1 __init__方法
下 面的 C 类(一个 new-style class)中, 从 object 继承来的原始 __init__方法, 可以认为就是一个 pass 语句, 因为它几乎什么都不做, 建议你在所有的 new-style class 中重新实现 __init__ 方法.
1 class C(object):
2 def __init__(self): pass
3 # rest of class body omitted
示 例中的的类只允许无参数调用,硬要传递一个参数给它会产生异常(如用C('xyz')). 如果C没有重载__init__方法, 调用C('xyz')会象 'xyz' 根本不存在一样忽略参数继续执行. 注意: (根据我的试验,2.4版中这点发生了变化,即使没有重载__init__方法,象C('xyz')这样调用一样会引发异常)
1.4.2. 5.2.3.2 __new__方法
每一个 new-style class 都有一个名为__new__的静态方法. 当你调用 C(*args,**kwds)创建一个C实例时,python内部调用的是 C.__new__(C,*args,**kwds).
new方法的返回值 x 就是该类的实例. 在确认 x 是C的实例以后, python调用C.__init__(x,*args,**kwds)来初始化这个实例. 也就是说,对新类C来讲,语句 x=C(23)等同于:
1 x = C.__new__(C, 23)
2 if isinstance(x, C): C.__init__(x, 23)
object.__new__ 创建一个新的,未初始化的类实例,它接收传递过来的第一个参数(也就是类对象本身),忽略其它的参数.当你重载__new__方法时,你不必使用函数修饰符@staticmethod, python解释器根据上下文会认出__new__()方法是一个静态方法. 如果你需要重绑定 C.__new__方法,你只需要在类外面执行 C.__new__=staticmethod(你想使用的新方法)就可以了.(极少有这样的需求)
__new__方法拥有函数工厂的绝大部分弹性.根据实际需求,我们可以让__new__返回一个已有的实例或者创建一个新的实例.
下面举一个通过重载__new__方法实现独身对象的设计模式的例子:
1 class Singleton(object):
2 _singletons = {}
3 def __new__(cls, *args, **kwds):
4 if not cls._singletons.has_key(cls): #若还没有任何实例
5 cls._singletons[cls] = object.__new__(cls) #生成一个实例
6 return cls._singletons[cls] #返回这个实例
Singleton的所有子类(当然是没有重载__new__方法的子类)都只可能有一个实例. 如果该类的子类定义了一个__init__方法,那么它必须保证它的__init__方法能够安全的对同一实例进行多次调用.
1.5. 5.2.4 new-style class 实例
new-style class 实例除了拥有 Classic class 实例的全部特性之外,还拥有一种称为property的新属性及一个叫作__slots__的特殊属性,该属性会对实例其它属性的访问产生重要影响.
新的对象模型同样添加了一个新的方法 __getattribute__ 比原有的 __getattr__ 方法更通用. 不同的实例可以拥有这些特殊方法的不同实现.
1.5.1. 5.2.4.1 Properties
property 是实例中具有特殊功能的属性. 你可以使用常规语法对property进行引用,绑定或解除绑定.如:
1 print x.prop
2 x.prop=23
3 del x.prop
然而,property如果只有这点功能那就和普通属性没什么两样了,property有它的独到之处,请往下读. 下面介绍如何定义一个只读property:
1 class Rectangle(object):
2 def __init__(self, width, heigth):
3 self.width = width
4 self.heigth = heigth
5 def getArea(self):
6