Python之内建方法 new 与 init

调用时机

创建类对象的过程中,首先调用new方法生成对象实例,然后自动(隐式)回调init方法。

为什么需要new方法?

init方法在实例化后执行,控制私有地址空间的值的初始化过程。
new方法在实例化前执行,控制类实例化的过程。有些属性在类实例化后将不可更改,只能在实例化过程去改变。不仅仅是操控属性,甚至改变输出,返回任意类实例。

new方法如何改变属性?

场景

如果子类继承了int、str、tuple这类不可变类型,可以通过new方法改变其属性

原理

不可变类型的特点是实例化后,属性无法被更改。如a = 10,执行new的阶段会在内存中开辟了一个地址块存放10这个值,之后无法再修改这个地址块的值。因此自定义赋值逻辑应当在new方法中执行。

实现

class PositiveInteger(int):
    """构造一个永远为正的整数类型"""
    def __new__(cls, value, *args, **kwargs):
        # new方法开辟内存空间,存放value的值,此后不允许在修改这块内存空间的值
        return super(PositiveInteger, cls).__new__(cls, abs(value), *args, **kwargs)

new方法如何改变返回的类实例?

场景

随便举几个例子:

  • 单例模式(概念不再赘述,懂的都懂)
  • 通过Book类创建对象,根据参数的类型和数量等自动分类为SportBook、ScienceBook、ArtBook

实现

class GlobalMaster(object):
    """构造一个单例模式的类
    
    类属性instance保存本类的实例化对象,类属性和对象属性的区别此处不再赘述
    """
    instance = None

    def __new__(cls, *args, **kwargs):
        if not cls.instance:
            cls.instance = super(GlobalMaster, cls).__new__(cls)
        # 只要运行于同一个进程空间,类的实例化返回的永远是同一个对象
        return cls.instance


class Book(object):
    """构造一个书籍类的实例化总入口,根据参数返回不同的书籍类对象

    例子中省略了SportBook等类的创建,都是普通地`clss SportBook:`写法。
    Book类承担的是分类功能,`a = Book("sport")`之后,a.rent()和a.return()等方法调用的都是SportBook的方法,而不是Book的方法。
    """
    def __new__(cls, value, *args, **kwargs):
        if value == "sport":
            return super(Book, cls).__new__(SportBook)
        elif value == "science":
            return super(Book, cls).__new__(ScienceBook)
        elif value == "art":
            return super(Book, cls).__new__(ArtBook)
        else:
            raise ValueError(f"未知的书籍类型: {value}")

参考链接

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容