http://www.cafepy.com/article/python_types_and_objects/python_types_and_objects.html
关于新类的更多特性和使用方法,参考:
Unifying types and classes in Python 2.2
How-To Guide for Descriptors
http://hi.baidu.com/mirguest/blog/item/a6da9f64ed0bc42bab184c32.html
http://wiki.woodpecker.org.cn/moin/PyNewStyleClass
new-style classes的使用
new-style classes提供了一些新的特殊方法,让我们可以更好地控制类的行为。
下面,我们讲几个常用的:
1.__new__:
__init__用来控制类的实例的初始化,而__new__控制初始化之前的行为---也就是实例的生成。
因此__new__的第一个参数是类(cls),而不是self。__new__的任务是返回一个所传入参数类(cls)的实例。
但,真正能够生成一个new-style class的实例的,只有object.__new__。因此我们定义的__new__,在需
要生成实例时,就应该调用它。
利用__new__的这个特性,我们可以很容易实现Singleton Pattern,让我们的类只会产生一个唯一的对象
>>> class Singleton(object):
__instance = None
def __new__(cls, *args, **kwd):
if Singleton.__instance is None:
Singleton.__instance = object.__new__(cls, *args, **kwd)
return Singleton.__instance
>>> class MyClass(Singleton):
pass
>>> a = MyClass()
>>> b = MyClass()
>>> a is b
True
>>> a is b is Singleton._Singleton__instance
True
通过继承,就可以使我自定义的类的行为符合Singleton Pattern的要求
2.__getattribute__:
__getattribute__比__getattr__对使用“.语法”(如obj.a)进行对象的属性和方法的读取操作提供了更强大的控制。
任何obj.a,都会被直接转化为obj.__getattribute__(a),包括__dict__。因此,在__getattribute__的实现,我们
不能直接用使用__dict__(那会造成循环调用),而应该的把真正的读取操作交给object.__getattribute__。
>>> class MyClass(object):
def __getattribute__(self, name):
print "accessing", name
return object.__getattribute__(self, name)
>>> a = MyClass()
>>> a.__dict__
accessing __dict__
{}
3.__get__,__set__,__delete__:
重载这三个方法,可以实现对类属性的读写控制
class RevealAccess(object):
"""A data descriptor that sets and returns values
normally and prints a message logging their access.
"""
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print 'Retrieving', self.name
return self.val
def __set__(self, obj, val):
print 'Updating' , self.name
self.val = val
>>> class MyClass(object):
x = RevealAccess(10, 'var "x"')
y = 5
>>> m = MyClass()
>>> m.x
Retrieving var "x"
10
>>> m.x = 20
Updating var "x"
>>> m.x
Retrieving var "x"
20
>>> m.y
5
可以用内建函数property,简化上述步骤
>>> class MyClass(object):
def __init__(self):
self.__x = 1
def getx(self):
print "Retrieving x"
return self.__x
def setx(self, value):
print "Updating x"
self.__x = value
def delx(self):
print "Deleting x"
del self.__x
x = property(getx, setx, delx, "I'm the x property")
>>> m = MyClass()
>>> m.x
Retrieving x
1
>>> m.x = 2
Updating x
>>> del m.x
Deleting x
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__方法能够安全的对同一实例进行多次调用.