许多人认为__init()__方法是类的构造方法,其实不然.__init__()方法所做的工作是在类的对象创建好之后进行变量的初始化.__new__()方法才会真正创建实例,是类的构造方法.这两个方法都是object类中默认的方法,继承自object的新式类,如果不覆盖这两个方法将会默认调用object中对应的方法.

__new__()__init()__的定义:

  • object.__new__(cls[,args...]):其中cls代表类,args为参数列表.
  • object.__init__(self[,args...]):其中self代表实例对象,args为参数列表.

不同之处:

  • __new__()方法为静态方法,__init__()方法为实例方法.
  • __new__()方法一般需要返回类的对象,当返回类的对象时将会自动调用__init__()方法进行初始化,如果没有对象返回,则__init__()方法不会被调用.__init__()方法不需要显示返回,默认为None,否则会在运行时抛出TypeError.
  • 当需要控制实例创建的时候可使用__new__()方法,而控制实例初始化的时候用__init__()方法.
  • 一般情况下不需要覆盖__new__()方法,但当子类继承自不可变类型,如str,int,unicode或者tuple的时候,往往需要覆盖该方法.
  • 当需要覆盖__new__()__init()__方法的时候这两个方法的参数必须保持一致,如果不一致将导致异常.

__new__()方法很少可以用到,有以下几种情况:

  1. 当类继承(如str,int,unicode,tuple或者forzenset等)不可变类型且默认的__new__()方法不能满足需求的时候.
  2. 用来实现工厂模式或者单例模式或者进行元类编程的时候.
  3. 作为用来初始化的__init__()方法在多继承的情况下,子类的__init__()方法如果不显式调用父类的__init__()方法,则父类的__init__()方法不会被调用.

new方法举例

举个工厂模式的例子:

class ShapeFactory(object):
    shapes = {'triangle': Triangle, 'rectangle': Rectangle}
    def __new__(klass, name):
        if name in ShapeFactory.shapes.keys():
            print "creating a new shape %s" % name
            return ShapeFactory.shapes[name]()
        else:
            print "creating a new shape %s" % name
            return Shape()

class Shape(object):
    def __init__(object):
        pass
    def draw(self):
        pass

class Triangle(Shape):
    def __init__(self):
        print "I am a triangle"
    def draw(self):
        proint "I am drawing triangle"

class Rectangle(Shape):
    def __init__(self):
        print "I am a rectangle"
    def draw(self):
        proint "I am drawing tectangle"

在ShapeFactory类中重新覆盖了__new__()方法,外界通过调用该方法来创建其所需要的对象类型,但如果所请求的类是系统所不支持的,则返回Shape对象.在引入了工厂类之后,只需要用如下形式就可以创建不同的图形对象:

ShapeFactory('rectangle').draw()

另一个继承不可变类型的例子:

class UserSet(frozenset):

    def __init__(self, arg=None):
        if isinstance(arg,basestring):
            arg = arg.split()
        frozenset.__init__(self, arg)


print UserSet("I am testing")
print frozenset("I am testing")

输出:

UserSet(['a', ' ', 'e', 'g', 'I', 'm', 'n', 'i', 's', 't'])
frozenset(['a', ' ', 'e', 'g', 'I', 'm', 'n', 'i', 's', 't'])

注意:为什么举这个例子呢,因为我们print UserSet("I am testing")输出的是实例的值,而不是__init__()的值,所以必须在__new__()过程中(生成实例时)进行更改,才能输出我们想要的值.

在UserSet中加入下面的

def __new__(cls, *args):
    if args and isinstance(args[0], basestring):
        args = (args[0].split(),) + args[1:]
    return super(UserSet, cls).__new__(cls, *args)

输出:

UserSet(['I', 'testing', 'am'])
frozenset(['a', ' ', 'e', 'g', 'I', 'm', 'n', 'i', 's', 't'])

总结

实例化一个类的过程:

  1. 检查是否有__new__()方法,如果没有就继承父类的__new__()方法;如果有则用自己的__new__()方法.
  2. 如果__new__()方法有返回值(类实例)则调用__init__()方法;如果没有则不掉用.

其实__new__()方法就是构造函数,是这个类实例的构造(实例参数类型),而__init__()方法是对实例初值进行赋值.大多数情况下我们可以用__init__()完成任务,但是上面那几种情况就需要__new__()方法.

Use __new__ when you need to control the creation of a new instance. Use __init__ when you need to control initialization of a new instance. __new__ is the first step of instance creation. It's called first, and is responsible for returning a new instance of your class. In contrast, __init__ doesn't return anything; it's only responsible for initializing the instance after it's been created. In general, you shouldn't need to override __new__ unless you're subclassing an immutable type like str, int, unicode or tuple.

From: http://mail.python.org/pipermail/tutor/2008-April/061426.html