深入理解__init__和__new__

前言

文章内容为understanding-new-and-init的译文。

本文的目的是讨论Python中的 __new____init__

__new____init__ 的区别表现在:1、自身的区别 2、老式类和新式类在Python中的定义

理解 __new____init__ 的区别

两者的主要区别是,__new__ 负责处理对象的创建,__init__ 负责处理对象的初始化。 在对象的实例化过程中,两个方法在定义不同时,工作方式略有不同。

Python2中的类

Python2中有新式类和老式类之分。老式类出现在Python3问世前, 定义时不继承基类 object, 而是默认继承 type,新式类则直接显示继承 object

Python2中的老式类:

class A:  # -> inherits from 'type'
    pass

Python2中的新式类

class A(object):  # -> clearly inherits from 'object'
    pass

Python3中没有新式类和老式类的区分,所有的的类直接继承自 object, 因此没有显示地指出 object 作为基类的必要。 object基类的方法和属性,通用于所有新式类。

在文章的其它部分,我们将讨论 __new____init__ 方法在两种情况下的区别: 它们如何表现如何使用它们

处理不同的情况

在深入实际的实现之前,你需要知道 __new__(类方法)接收 cls 作为第一个参数, __init__ 接收 self 作为第一个参数。 当调用 __new__ 时, 实际上你还没有获得一个实例, 所以此刻 self 并不存在。 而 __init____new__ 创建并返回一个实例 之后调用, 此时实例已经创建可用,所以你可以传递使用 self

老式类中的 __new____init__

老式类实际上没有 __new__ 方法,因为 __init__ 就是它们的构造函数,所以我们可以尝试:

class A:

    def __new__(cls):
        print "A.__new__ is called"  # -> this is never called

A()

在这种情况下, __new__ 方法不永远不会被执行, 因为它不是老式类目标函数。

如果我们使用重写 __init__ 的方式来替代:

class A:

    def __init__(self):
        print "A.__init__ called"

A()

输出将会是:

A.__init__ called

现在让我们尝试让 __init__ 返回一个值:

class A:

    def __init__(self):
        return 29

A()

这会导致一个异常:

TypeError: __init__() should return None

这意味着在实例化老式类的时,我们实际上不能控制它的返回。

新式类中的 __new____init__

新式类可以让开发者同时重写 __new____init__ ,两者有不同的用处, __new__(构造函数) 单一的创建对象,__init__ (初始化函数) 初始化这个对象。

让我们看下它们的执行顺序:

class A(object):  # -> don't forget the object specified as base

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

    def __init__(self):
        print "A.__init__ called"

A()

输出如下:

A.__new__ called
A.__init__ called

你也许想要知道 __new____init__ 在何处被调用,我能告诉你的是,在调用类名时(实例化期间) __new__ 被自动调用。而 __init__ 则在每次 __new__ 返回类的实例时调用,并将返回的实例作为 self 参数传递给 __init__即使你将创建的实例保存成全局或者静态对象, 并且在每次调用 __new__后返回这个对象,__init__依然每次会被调用

知道这个意味着如果我们在 __new__ 忽略调用基类的 super(A, cls).__new__(cls),会导致 __init__ 不被执行。让我们看看下面这种情况:

class A(object):

    def __new__(cls):
        print "A.__new__ called"

    def __init__(self):
        print "A.__init__ called"  # -> is actually never called

print A()

输出结果为:

A.__new__ called
None

很明显,当我们在构造器中不返回东西时,实例被认为是 None

想象下如果我们尝试让 __new__ 返回一些东西,会发生什么事情。

class A(object):

    def __new__(cls):
        print "A.__new__ called"
        return 29

print A()

输出结果为:

A.__new__ called
29

让我们看看当我们尝试让 __init__ 返回时,会发生什么:

class A(object):

    def __init__(self):
        print "A.__init__ called" 
            return 33  # -> TypeError: __init__ should return None

A()

触发了异常:

TypeError: __init__ should return None

这主要是因为调用 __init__ 的处理程序引发了 TypeError 异常,从 __init__ 返回东西没有意义,因为它的主要功能是更改新创建实例的状态。

看起来新式类给我们提供了更多的灵活性,允许我们在对象创建和初始化的前后做任何操作,并且允许我们控制实例化时返回的内容。

考虑到这一点,让我们在 __new__ 中返回另一个类的实例。

首先,我们定义一个待用的类:

class Sample(object):
    
    def __str__(self):
        return "SAMPLE"

然后, 我们定义一个重写 __new__ 的类:

class A(object):

    def __new__(cls):
        return Sample()

这个也可以写成如下形式:

class A(object):

    def __new__(cls):
        return super(A, cls).__new__(Sample)

接着调用:

print A()

输出为:

SAMPLE

简单总结:

Python3中 __new__ 负责对象的创建,__init__ 负责对象的初始化。

参考文章

转载于:https://www.cnblogs.com/soga238/p/10209525.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值