Python类的__new__()

本文深入解析Python中__new__和__init__方法的区别与联系,阐述__new__作为真正实例化方法的角色,及__init__在实例化后的初始化作用。通过类比建筑过程,形象说明两者在对象创建中的分工。

Python类的__new__()

 

  本篇主要想要详细的介绍一下关于类的魔法方法__new__()方法。

  在学习之前我们看一下Python3中关于object基类的__new__() 方法:

    @staticmethod # known case of __new__
    def __new__(cls, *more): # known special case of object.__new__
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

  上述描述:__new__()创建和返回一个新的对象。通俗说:该魔法属性是用来创建实例对象的。接下来我们看一下它的是如何创建对象的。

一、理解

  1、__new__()是在新式类中新出现的方法,它作用在构造方法建造实例之前。

  即可以这样理解:Python中存在于类中的构造方法__init__()负责将类实例化,而在__init__()执行之前,__new__()负责制造这样的一个实例对象,以便__init__()去让该实例对象更加的丰富(为其添加属性等)。

  同时:__new__() 方法还决定是否要使用该__init__() 方法,因为__new__()可以调用其他类的构造方法或者直接返回别的对象来作为本类 的实例。

  2、__new__() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器。

    比喻

  

  如果将类比喻为工厂,那么__init__()方法则是该工厂的生产工人,__init__()方法接受的初始化参 数则是生产所需原料,__init__()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而 __new__()则是生产部经理,__new__()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出 货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。

  

二、结构

  在Python中,若不重写类中的__new__()方法,其默认的结构时这样的:

class Foo(object):
    def __new__(cls,*args,**kwagrs):
        return super().__new__(cls,*args,**kwagrs)

  1、其第一个参数 cls 是当前正在实例化的类。 

  如果要得到当前类的实例,应当在当前类中的__new__()方法语句中调用当前类的父类 的__new__()方法。例如,如果当前类是直接继承自object,那当前类的__new__()方法返回的对象应该为:
class Foo(object):
    def __new__(cls,*args,**kwagrs):
        return object.__new__(cls,*args,**kwagrs)

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

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

class A(object):
    pass

class B(A):
    pass

class C(B):
    def __new__(cls,*args,**kwargs):
        return super().__new__(cls, *args,**kwargs)

        # 等同于:
        # return B.__new__(cls, *args,**kwargs)
        # return A.__new__(cls, *args,**kwargs)
        # return object.__new__(cls, *args,**kwargs)

  2、在任何新式类的__new__()方法,不能调用自身的__new__()来制造实例,因为这会造成死循环。

  例如:

class Bar(object):
    def __new__(cls,*agrs,**kwagrs):
        return Bar.__new__(Foo,*agrs,**kwagrs)

  这样的话会造成 当Bar调用其自身的__new__() 方法制造实例时,又会跳到第二行去执行__new__(),当到第三行时,又跳到第二行去调用__new__(),这样不断的就会陷入死循环。

  3、Bar.__new__(Foo,*agrs,**kwagrs) ,指:使用哪个类(bar)的__new__()方法去制造谁的(Foo)实例对象。

  通常来说,新式类开始实例化时,__new__()方法会返回cls(cls指代当前类)的实例,然后该类的 __init__()方法作为构造方法会接收这个实例(即self)作为自己的第一个参数,然后依次传入__new__ ()方法中接收的位置参数和命名参数。

  注:如果__new__()没有返回cls(即当前类)的实例,那么当前类的__init__()方法是不会被调用 的。如果__new__()返回其他类(新式类或经典类均可)的实例,那么只会调用被返回的那个类的构造方 法。
class Foo(object):
    def __new__(cls,*args,**kwagrs):
        return object.__new__(cls,*args,**kwagrs)
    
    def __init__(self,name):
        self.name = name

class Bar(object):
    def __new__(cls,*agrs,**kwagrs):
        return object.__new__(Foo,*agrs,**kwagrs)
    
bar = Bar()
print(type(bar)) #foo其实是Stranger类的实例。

# 输出为:<class '__main__.Foo'>

   会发现上例:制造的是Foo的实例对象。

 

  总结:因此可以这么描述__new__()和__ini__()的区别,在新式类中__new__()才是真正的实例化方法,为类提供外壳制造出实例框架,然后调用该框架内的构造方法__init__()使其丰满。

    如果以建房子做比喻,__new__()方法负责开发地皮,打下地基,并将原料存放在工地。而__init__()方法负责从工地取材料建造出地皮开发招标书中规定的大楼,__init__()负责大楼的细节设计,建造,装修使其可交付给客户。

 

posted @ 2018-09-21 22:13 Little_five 阅读( ...) 评论( ...) 编辑 收藏
### Python 中 `__new__` 方法的作用 在 Python 的实例化过程中,`__new__` 方法负责创建并返回一个新的实例。这个方法是一个静态方法,在调用时需要主动传递 `cls` 参数[^1]。 当重写 `__new__` 方法时,通常会调用父的 `__new__` 方法来完成实际的对象创建工作,并最终返回该对象。如果不返回一个新创建的对象,则不会触发后续的 `__init__` 初始化操作[^2]。 #### 创建对象的具体流程如下: - 首先执行 `__new__` 来构建新的实例; - 如果 `__new__` 返回的是当前的新实例,则继续调用此实例上的 `__init__` 进行初始化设置;否则跳过这一步骤[^4]。 ### 自定义 `__new__` 实现特定功能的例子 下面给出一段简单的代码片段用于演示如何利用 `__new__` 定制的行为——这里实现了单例模式下的实例共享机制。 ```python class Singleton(object): _instance = None def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton, cls).__new__(cls) return cls._instance s1 = Singleton() s2 = Singleton() print(s1 is s2) # 输出 True 表明两次获取到同一个实例 ``` 这段程序展示了通过覆盖默认的 `object.__new__()` 函数可以改变原有逻辑,使得每次请求都指向同一份数据副本而不是各自独立的一份拷贝。 另外还提供了一个更完整的例子,包含了 `__new__`, `__init__` 和 `__call__` 的基本应用方式[^3]: ```python class ClassA: def __new__(cls): print('ClassA.__new__') instance = super().__new__(cls) return instance def __init__(self): print('ClassA.__init__') def __call__(self, *args): print(f'ClassA.__call__ args: {args}') a = ClassA() # 执行顺序:ClassA.__new__, ClassA.__init__ result = a(1, 2, 3)# 调用了可调用对象协议即 ClassA.__call__ ``` 在这个案例里可以看到三个特殊成员函数之间的协作关系,其中 `__new__` 控制着最基础层面的对象生成动作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值