目录
__new__ 是对象实例化时调用的第一个方法,调用以创建一个 cls 类的新实例;
__new__ 将所请求实例所属的类作为第一个参数,即 cls 参数,其他参数会直接传给 __init__ 方法;
__new__ 通常不需要重写,默认执行即可;如果重写,一般用于允许不可变类型的子类 (例如 int, str 或 tuple) 定制实例创建过程,也常会在自定义元类中被重载以便定制类创建过程;
典型的实现会附带适宜的参数使用 super().__new__(cls[, ...]),通过父类的 __new__ 方法创建一个类的新实例,然后根据需要修改新创建的实例再将其返回。
- #创建不可变类型 tuple 的子类
- class Newtest(tuple):
-
- #调用 __new__ 方法,改写子类在对象实例化时操作
- def __new__(cls, inputtuple):
- inputtuple = inputtuple + ('default element',)
- #返回 super().__new__(cls[, ...]),通过父类的 __new__ 方法创建修改后子类的新实例
- return super().__new__(cls, inputtuple)
-
- #调用子类创建实例,执行成功
- tuplex = (1,2,3)
- tupley = Newtest(tuplex)
- tupley
- (1, 2, 3, 'default element')
在实例(通过 __new__ 方法)被创建之后,返回调用者之前调用,其参数与传递给类构造器表达式的参数相同,相当于其他面向对象编程语言的构造方法;
实例对象由 __new__ 创建、__init__ 定制, 两个方法协作完成实例对象的构造,__init__ 返回值只能为 None,否则会在构造实例对象时报错;
如一个父类有重写的 __init__ 方法,其派生的子类如果也有重写 __init__ 方法,则需要在子类的 __init__ 方法中确保实例对象构造中父类部分的正确初始化,如添加 super().__init__([args...]) 代码段。
- #创建类的 __init__ 方法有返回值
- class Inittest():
- def __init__(self, name):
- self.name = name
- return self.name
-
- #构造实例对象时报错
- testx = Inittest('abc')
- Traceback (most recent call last):
- File "<input>", line 1, in <module>
- TypeError: __init__() should return None, not 'str'
-
- #创建父类
- class Inittest():
- def __init__(self, name):
- self.name = name
- #创建不带父类初始化的子类1
- class Initderived1(Inittest):
- def __init__(self, value):
- self.value = value
- #创建带父类初始化的子类2
- class Initderived2(Inittest):
- def __init__(self, name, value):
- super().__init__(name)
- self.value = value
-
- #子类1构建实例,调用父类初始化赋值变量失败
- test1 = Initderived1('abc')
- test1.name
- Traceback (most recent call last):
- File "<input>", line 1, in <module>
- AttributeError: 'Initderived1' object has no attribute 'name'
-
- #子类2构建实例,调用父类、子类初始化赋值变量成功
- test2 = Initderived2('wow','abc')
- test2.name
- 'wow'
- test2.value
- 'abc'
__del__ 方法在实例将被销毁时调用,相当于其他面向对象编程语言的析构方法;
del object 不等于自动调用 object.__del__(),只有当垃圾回收机制回收这个对象时,才会调用 __dell__ 方法;即需要清除所有指向 object 实际地址的所有对象,开启垃圾回收机制, __dell__ 方法才开始执行;
当构建实例对象失败时,也会自动调用 __del__ 方法;
如一个父类有重写的 __del__ 方法,其派生的子类如果也有重写 __del__ 方法,则需要在子类的 __del__ 方法中确保删除实例对象时对其父类部分的正确析构,如添加 super().__del__(self) 代码段。
__del__ 方法可以(但不推荐!)通过创建一个该实例的新引用来推迟其销毁,这被称为对象重生。__del__() 是否会在重生的对象将被销毁时再次被调用是由具体实现决定的,当前的 CPython 实现只会调用一次。
- #创建父类
- class Deltest():
- def __init__(self, name):
- self.name = name
-
- def __del__(self):
- print(f'调用父类 del 方法')
- #创建不带父类析构方法的子类
- class Delderived1(Deltest):
- def __del__(self):
- print('调用子类1 del 方法')
- #创建带父类析构方法的子类
- class Delderived2(Deltest):
- def __del__(self):
- super().__del__()
- print('调用子类2 del 方法')
-
- #构建实例对象失败,调用 __del__ 方法
- test1 = Deltest()
- 调用父类 del 方法
- Traceback (most recent call last):
- File "<input>", line 1, in <module>
- TypeError: __init__() missing 1 required positional argument: 'name'
-
- #调用不带父类析构方法的子类,没有执行父类 __del__ 方法
- test1 = Delderived1('test1')
- del test1
- 调用子类1 del 方法
- #调用带父类析构方法的子类,执行父类 __del__ 方法
- test2 = Delderived2('test2')
- del test2
- 调用父类 del 方法
- 调用子类2 del 方法
-
- #只有当垃圾回收机制回收这个对象时,才会调用 __dell__ 方法
- test31 = Deltest('test')
- test32 = test31
- test33 = test32
- del test31
- del test33
- del test32
- 调用父类 del 方法