魔法方法(三)


new()

首先,只有新式类才有魔法方法__new__(),从Object类继承的子类,都是新式类。

object类关于__new__()的定义如下:

@staticmethod # known case of __new__
    def __new__(cls, *more): # known special case of object.__new__
        """ T.__new__(S, ...) -> a new object with type S, a subtype of T """
        pass
参数说明:

(1)object将__new__()定义成静态方法。

(2)传入的参数至少一个cls参数,cls表示需要实例化的类。

如何使用,举个例子:

class A(object):
    def __init__(self, value):
        print  "into __init__"
        self.value = value
    def __new__(cls, *args, **kwargs):
        print "into __new__"
        return super(A, cls).__new__(cls, *args, **kwargs)
 
a =  A(10)
 
# 结果如下:
# into __new__
# into __init__

可发现,在调用__init__()初始化前,先调用了__new__()。

在新式类中,new()对当前类进行了实例化,并将实例返回,传给了__init__(),init()方法中是self就是__new__()传过来的。

但是,执行了__new__(),并不一定会进入__init__(),只有__new__()返回了,当前类cls的实例,当前类的__init__()才会进入。

看两个例子:

class A(object):
    def __init__(self, value):
        print  "into A __init__"
        self.value = value
        
    def __new__(cls, *args, **kwargs):
        print "into A __new__"
        return object.__new__(cls, *args, **kwargs)
 
 
class B(A):
    def __init__(self, value):
        print  "into B __init__"
        self.value = value
        
    def __new__(cls, *args, **kwargs):
        print "into B __new__"
        return super(B, cls).__new__(cls, *args, **kwargs)
 
b = B(10)
 
b = B(10)
# 结果:
# into B __new__
# into A __new__
# into B __init__
 
 
 
class A(object):
    def __init__(self, value):
        print  "into A __init__"
        self.value = value
 
    def __new__(cls, *args, **kwargs):
        print "into A __new__"
        return object.__new__(cls, *args, **kwargs)
 
 
class B(A):
    def __init__(self, value):
        print  "into B __init__"
        self.value = value
 
    def __new__(cls, *args, **kwargs):
        print "into B __new__"
        return super(B, cls).__new__(A, *args, **kwargs) #改动了cls变为A
 
b = B(10)
# 结果:
into B __new__
into A __new__

若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行,将没有__init__被调用。

__new__的作用

(1)

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

假如我们需要一个永远都是正数的整数类型。

lass PositiveInteger(int):
    def __init__(self, value):
        super(PositiveInteger, self).__init__(self, abs(value))
 
 
i = PositiveInteger(-3)
print i
 
# -3
 
class PositiveInteger(int):
    def __new__(cls, value):
        return super(PositiveInteger, cls).__new__(cls, abs(value))
 
 
i = PositiveInteger(-3)
print i
 
# 3
通过重载__new__方法,我们实现了需要的功能。

(2)实现单例

一些说明:

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

(2)除了一项两个作用外,一般__new__()使用较少,能通过__init__()实现的尽量用__init__()实现。

new()—>2

我们首先得从__new__(cls[,…])的参数说说起,__new__方法的第一个参数是这个类,而其余的参数会在调用成功后全部传递给__init__方法初始化,这一下子就看出了谁是老子谁是小子的关系。

所以,__new__方法(第一个执行)先于__init__方法执行:

class A:
	pass
 
class B(A):
	def __new__(cls):
		print("__new__方法被执行")
		return super().__new__(cls)
	def __init__(self):
		print("__init__方法被执行")
 
b = B()
执行结果为:

__new__方法被执行
__init__方法被执行

我们比较两个方法的参数,可以发现__new__方法是传入类(cls),而__init__方法传入类的实例化对象(self),而有意思的是,__new__方法返回的值就是一个实例化对象(ps:如果__new__方法返回None,则__init__方法不会被执行,并且返回值只能调用父类中的__new__方法,而不能调用毫无关系的类的__new__方法)。我们可以这么理解它们之间的关系,__new__是开辟疆域的大将军,而__init__是在这片疆域上辛勤劳作的小老百姓,只有__new__执行完后,开辟好疆域后,__init__才能工作,结合到代码,也就是__new__的返回值正是__init__中self。

我们可以看下面这个例子:

class CapStr(str):
    def __new__(cls, string):
        self_in_init = super().__new__(cls, string)
        print(id(self_in_init))
        return self_in_init
    def __init__(self,string):
        print(id(self))
 
a = CapStr("I love China!")
print(id(a))
执行结果为:

2691640428616
2691640428616
2691640428616

上面这段代码的内容很简单,在__new__中打印一下返回值的id,在__init__中打印一下self的id值,最后再打印一下创建的这个类的id值(所谓的id值也就是内存地址),我们可以看到最后的输出结果是一致的,这也就说明,整个类的地盘是由__new__函数"开辟出来的",而到了__init__内部就只能在这片地盘上"修修补补"了。

小结:__new__和__init__相配合才是python中真正的类构造器。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值