__init__与__new__区别:

__new__:创建对象时调用,会返回当前对象的一个实例

摘要

本文讨论了Python中__init____new__方法。

__new____init__具有不同的功能。并且对于Python的新类和旧类而言功能也不同。

1 class A(object):
2     def __init__(self,*args, **kwargs):
3         print "init A"
4     def __new__(cls,*args, **kwargs):
5         print "new A %s"%cls
6      #return super(A, cls).__new__(cls, *args, **kwargs)
7         return object.__new__(cls, *args, **kwargs)

请运行代码:

__init__在python,其实是,在实例化之后执行的,用来初始化一些属性,相当于构造函数,但是又不一样

__init__:创建完对象后调用,对当前对象的一些实例初始化,无返回值

__new____init__功能上的区别

__new____init__的主要区别在于:__new__是用来创造一个类的实例的(constructor),而__init__是用来初始化一个实例的(initializer)。

说明

class A:
    def __init__(self):
        print "A.__init"

    def __new__(self):
        print "A.__new"


class B(object):
    def __init__(self):
        print "B.__init"
        super(B, self).__init__()

    def __new__(cls):
        print "B.__new__"
        return super(B,cls).__new__(cls)


a = A()
b = B()
print(type(a))
print(type(b))

细心一些,通过参数会有所发现,其实__init__(self)
 self隐式的将,实例传过来。

1、在类中,如果__new__和__init__同时存在,会优先调用__new__

Python的新类和旧类

Python中的类分为新类和旧类。旧类是Python3之前的类,旧类并不是默认继承object类,而是继承type类。

Python2中的旧类如下面代码所示:

class oldStyleClass: # inherits from 'type'
    pass

Python2中定义一个新类:

class newStyleClass(object): # explicitly inherits from 'object'
    pass

在Python3中所有的类均默认继承object,所以并不需要显式地指定object为基类。

object为基类可以使得所定义的类具有新类所对应的方法(methods)和属性(properties)。

在下面的文章中我们会分别基于新类和旧类探讨__new____init__

1、继承自object的新式类才有__new__

运行结果

 

>>> class Data(object):
...     def __new__(self):
...             print "new"
...     def __init__(self):
...             print "init"
... 
>>> data = Data()
new

__new____init__参数的不同

__new__所接收的第一个参数是cls,而__init__所接收的第一个参数是self。这是因为当我们调用__new__的时候,该类的实例还并不存在(也就是self所引用的对象还不存在),所以需要接收一个类作为参数,从而产生一个实例。而当我们调用__init__的时候,实例已经存在,因此__init__接受self作为第一个参数并对该实例进行必要的初始化操作。这也意味着__init__是在__new__之后被调用的。

2、__new__至少要有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别

A.__init
B.__new__
B.__init
<type ‘instance’>
<class ‘__main__.B’>

__new__在python中其实是,在实例化之前执行的,这个通过参数一样可以看出

2、__new__方法会返回所构造的对象,__init__则不会。__init__无返回值。

Python旧类中的__new____init__

Python的旧类中实际上并没有__new__方法。因为旧类中的__init__实际上起构造器的作用。所以如果我们定义如下旧类:

class oldStyleClass:
    def __new__(cls):
        print("__new__ is called") # this line will never get called during construction

oldStyleClass()

程序输出结果如下:

<__main__.oldStyleClass instance at 0x109c45518>

可见创建及初始化对象的过程并没有调用__new__。实际上,除非显式调用:oldStyleClass.__new__(oldStyleClass),该类中的__new__方法中的内容永远不会被调用。因为旧类构造实例并不会调用__new__方法。

但如果我们重载__init__方法:

class oldStyleClass:
    def __init__(self):
        print("__init__ is called")

oldStyleClass()

该程序将会输出

__init__ is called
<__main__.oldStyleClass instance at 0x1091992d8>

如果我们在__init__中加上return语句,将会导致TypeError: __init__() should return None的错误。

class oldStyleClass:
    def __init__(self):
        return 29

oldStyleClass()

程序结果如下:

TypeError: __init__() should return None

这意味着对于Python的旧类而言,我们无法控制__init__函数的返回值。

3、__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类(通过super(当前类名,
cls))__new__出来的实例,或者直接是object的__new__出来的实例

请注意:  A无基类,B有基类并且__new__
方法跟__init__两个方法有两点不同

__new__(cls),cls是隐式的传递的类对象,并不是实例。因为__new__的任务就是,创建类实例并返回实例。

>>> class Data(object):
...     def __init__(cls):
...             cls.x = 2
...             print "init"
...             return cls
... 
>>> data = Data()
init
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() should return None, not 'Data'

>>> class Data(object):
...     def __new__(cls):
...             print "new"
...             cls.x = 1
...             return cls
...     def __init__(self):
...             print "init"
... 
>>> data = Data()
new
>>> data.x =1 
>>> data.x
1

If __new__() returns an instance of cls, then the new instance’s __init__() method will be 
invoked like __init__(self[, ...]), where self is the new instance and the remaining 
arguments are the same as were passed to __new__().

如果__new__返回一个对象的实例,会隐式调用__init__

If __new__() does not return an instance of cls, then the new instance’s __init__() method
 will not be invoked.

如果__new__不返回一个对象的实例,__init__不会被调用

Python新类中的__new____init__

Python的新类允许用户重载__new____init__方法,且这两个方法具有不同的作用。__new__作为构造器,起创建一个类实例的作用。而__init__作为初始化器,起初始化一个已被创建的实例的作用。

如下面代码是所示:

class newStyleClass(object): 
    # In Python2, we need to specify the object as the base.
    # In Python3 it's default.

    def __new__(cls):
        print("__new__ is called")
        return super(newStyleClass, cls).__new__(cls)

    def __init__(self):
        print("__init__ is called")
        print("self is: ", self)

newStyleClass()

结果如下:

__new__ is called
__init__ is called
self is: <__main__.newStyleClass at 0x109290890>
<__main__.newStyleClass at 0x109290890>

创建类实例并初始化的过程中__new____init__被调用的顺序也能从上面代码的输出结果中看出:__new__函数首先被调用,构造了一个newStyleClass的实例,接着__init__函数在__new__函数返回一个实例的时候被调用,并且这个实例作为self参数被传入了__init__函数。

这里需要注意的是,如果__new__函数返回一个已经存在的实例(不论是哪个类的),__init__不会被调用。如下面代码所示:

obj = 12 
# obj can be an object from any class, even object.__new__(object)

class returnExistedObj(object):
    def __new__(cls):
        print("__new__ is called")
        return obj

    def __init(self):
        print("__init__ is called")

returnExistedObj()

执行结果如下:

__new__ is called
12

同时另一个需要注意的点是:

如果我们在__new__函数中不返回任何对象,则__init__函数也不会被调用。

如下面代码所示:

class notReturnObj(object):
    def __new__(cls):
        print("__new__ is called")

    def __init__(self):
        print("__init__ is called")

print(notReturnObj())

执行结果如下:

__new__ is called
None

可见如果__new__函数不返回对象的话,不会有任何对象被创建,__init__函数也不会被调用来初始化对象。

4、__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值

1.self,cls参数不同,即 __new__为classmethod.

class temp(object):

    def __init__(self,txt):
        self.txt = txt
        print '__init__'


    def __new__(cls,txt):
        print '__new__'
        print txt
        return super(temp,cls).__new__(cls)

temp('what?')

以下摘自《Python核心编程(第二版)》:

总结几个点

  1. __init__不能有返回值

  2. __new__函数直接上可以返回别的类的实例。如上面例子中的returnExistedObj类的__new__函数返回了一个int值。

  3. 只有在__new__返回一个新创建属于该类的实例时当前类的__init__才会被调用。如下面例子所示:

class sample(object):
    def __str__(self):
        print("sample")

class example(object):
    def __new__(cls):
        print("__new__ is called")
        return sample()

    def __init__(self):
        print("__init__ is called")

example()

输出结果为:

__new__ is called
sample

5、如果__new__创建的是当前类的实例,会自动调用__init__函数,通过return语句里面调用的__new__函数的第一个参数是cls来保证是当前类实例,如果是其他类的类名,;那么实际创建返回的就是其他类的实例,其实就不会调用当前类的__init__函数,也不会调用其他类的__init__函数。

2.__new__有return。

结果:

__init()__ “构造器”方法:

当类被调用,实例化的第一步是创建实例对象。一旦对象创建了,Python
检查是否实现了__init__()方法。默认情况下,如果没有定义(或覆盖)特殊方法__init__(),对实例不会施加任何特别的操作.任何所需的特定操作,都需要程序员实现__init__(),覆盖它的默认行为。如果__init__()没有实现,则返回它的对象,实例化过程完毕。
然而,如果__init__()已经被实现,那么它将被调用,实例对象作为第一个参数(self)被传递进去,像标准方法调用一样。调用类时,传进的任何参数都交给了__init__()。实际中,你可以想像成这样:把创建实例的调用当成是对构造器的调用。
总之,(a)你没有通过调用 new 来创建实例,你也没有定义一个构造器。是
Python 为你创建了对象; (b)
__init__(),是在解释器为你创建一个实例后调用的第一个方法,在你开始使用它之前,这一步可以让你做些准备工作。
__init__()是很多为类定义的特殊方法之一。其中一些特殊方法是预定义的,缺省情况下,不进行任何操作,比如__init__(),要定制,就必须对它进行重载,还有些方法,可能要按需要去实现。

 

这两个问题牵涉到概念New-style and classic
classes。请参照
style clas,两者是如何出现的。

C:\Python27\python.exe D:/weixin/temp/abc.py
__new__
what?
__init__

Process finished with exit code 0
__new()__ “构造器”方法:

与__init__()相比,__new__()方法更像一个真正的构造器。类型和类在版本
2.2 就统一了,Python
用户可以对内建类型进行派生,因此,需要一种途径来实例化不可变对象,比如,派生字符串,数字,等等。
在这种情况下,解释器则调用类的__new__()方法,一个静态方法,并且传入的参数是在类实例化操作时生成的。__new__()会调用父类的__new__()来创建对象(向上代理)。
为何我们认为__new__()比__init__()更像构造器呢?这是因为__new__()必须返回一个合法的实例,这样解释器在调用__init__()时,就可以把这个实例作为
self 传给它。调用父类的__new__()来创建对象,正像其它语言中使用 new
关键字一样。
__new__()和__init__()在类创建时,都传入了(相同)参数。13.11.3
节中有个例子使用了__new__()。

<class '__main__.B'>
>>> class A(object):
...     def __new__(Class):
...             object = super(A,Class).__new__(Class)
...             print "in New"
...             return object
...     def __init__(self):
...             print "in init"
... 
>>> A()
in New
in init
<__main__.A object at 0x7fa8bc622d90>
>>> class A(object):
...     def __new__(cls):
...             print "in New"
...             return cls
...     def __init__(self):
...             print "in init"
... 
>>> a = A()      
in New

object.__init__(self[, ...])
Called when the instance is created. The arguments are those passed to the class 
constructor expression. If a base class has an __init__() method, the derived 
class’s __init__() method, if any, must explicitly call it to ensure proper initialization 
of the base class part of the instance; for example: BaseClass.__init__(self, [args...]). 
As a special constraint on constructors, no value may be returned; doing so will cause a
TypeError to be raised at runtime.

在对象的实例创建完成后调用。参数被传给类的构造函数。如果基类有__init__方法,子类必须显示
调用基类的__init__。

没有返回值,否则会再引发TypeError错误。
原文:https://www.cnblogs.com/gsblog/p/3368304.html

在继承派生时的调用顺序

不管是new style或者classic都可以使用isinstance(obj, cls)做判断。

 

1 class B(A):
2     def __init__(self,*args, **kwargs):
3         print "init B"
4     def __new__(cls,*args, **kwargs):
5         print "new B %s"%cls
6      #return super(B, cls).__new__(cls, *args, **kwargs)
7         return object.__new__(cls, *args, **kwargs)

因为a虽然现实type
‘instance’。但是查看a.__class__仍然可以看到a的类型。

 

 

 

Linux and
python学习交流1,2群已满.

1、在定义子类时没有重新定义__new__()时,Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写__new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。

Linux and
python学习交流3群新开,欢迎加入,一起学习.qq 3群:563227894

2、而如果子类中重写了__new__()方法,那么你可以自由选择任意一个的其他的新式类(必定要是新式类,只有新式类必定都有__new__(),因为所有新式类都是object的后代,而经典类则没有__new__()方法)的__new__()方法来制造实例,包括这个新式类的所有前代类和后代类,只要它们不会造成递归死循环。反正肯定不能调用自己的__new__,这肯定是死循环。

不前进,不倒退,停止的状态是没有的.

3、对于子类的__init__,其调用规则跟__new__是一致的,当然如果子类和父类的__init__函数都想调用,可以在子类的__init__函数中加入对父类__init__函数的调用。

一起进步,与君共勉,

4、我们在使用时,尽量使用__init__函数,不要去自定义__new__函数,因为这两者在继承派生时的特性还是很不一样的。

 

 

__new__ 的作用

1、__new__方法主要是当你继承一些不可变的class时(比如int,
str, tuple), 提供给你一个自定义这些类的实例化过程的途径。

假如我们需要一个永远都是正数的整数类型,通过集成int,我们可能会写出这样的代码。

1 class PositiveInteger(int):
2     def __init__(self, value):
3         super(PositiveInteger, self).__init__(self, abs(value))
4 
5 
6 i = PositiveInteger(-3)
7 print i

但运行后会发现,结果根本不是我们想的那样,我们任然得到了-3。这是因为对于int这种
不可变的对象,我们只有重载它的__new__方法才能起到自定义的作用。
这是修改后的代码:

class PositiveInteger(int):
    def __new__(cls, value):
        return super(PositiveInteger, cls).__new__(cls, abs(value))


i = PositiveInteger(-3)
print i

通过重载__new__方法,我们实现了需要的功能。

2、实现单例

事实上,当我们理解了__new__方法后,我们还可以利用它来做一些其他有趣的事情,比如实现
设计模式中的 单例模式(singleton) 。
因为类每一次实例化后产生的过程都是通过__new__来控制的,所以通过重载__new__方法,我们
可以很简单的实现单例模式。

class Singleton(object):
    def __new__(cls):
        # 关键在于这,每一次实例化的时候,我们都只会返回这同一个instance对象
        if not hasattr(cls, 'instance'):
            cls.instance = super(Singleton, cls).__new__(cls)
        return cls.instance


obj1 = Singleton()
obj2 = Singleton()


obj1.attr1 = 'value1'
print obj1.attr1, obj2.attr1
print obj1 is obj2

输出结果:
value1 value1
True
可以看到obj1和obj2是同一个实例。

class Singleton(object):
    __instance = None


    def __init__(self, *args, **kwargs):
        pass


    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            # if not hasattr(cls, 'instance'):
            cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
            cls.__instance.aa = args[0]
            print type(cls), type(cls.__instance), type(cls.__instance.aa)
        return cls.__instance

obj1 = Singleton(1, 2, 3, b=2)
obj2 = Singleton(1, 2, 3, b=2)

obj1.attr1 = 'value1'
obj2.attr2 = 'value2'
print obj1.attr1, obj1.attr2
print obj1 is obj2
print obj1.aa, obj2.attr1 

结果:
<type ‘type’> <class ‘__main__.Singleton’> <type
‘int’>
value1 value2
True
1 value1

 

3、实现自定义的metaclass。

 

 

参考链接:

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图