new()是在新式类中新出现的方法, 它作用在构造方法 init()建造实例之前, 可以这么理解, 在 Python 中存在于类里面的构造方法 init()负责将类的实例化, 而在 init()调用之前, new()决定是否要使用该 init()方法, 因为 new()可以调用其他类的构造方法或者直接返回别的对象来作为本类 的实例.
如果将类比喻为工厂, 那么 init()方法则是该工厂的生产工人, init()方法接受的初始化参 数则是生产所需原料, init()方法会按照方法中的语句负责将原料加工成实例以供工厂出货. 而 new()则是生产部经理, new()方法可以决定是否将原料提供给该生产部工人, 同时它还决定着出 货产品是否为该生产部的产品, 因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品.
new()方法的特性:
new()方法是在类准备将自身实例化时调用.
new()方法始终都是类的静态方法, 即使没有被加上静态方法装饰器.
综上所述, 当 new 需要接受一个参数的时候, init 在初始化的时候就必须为其提供参数, 例如:
- # 定义一个类, 并且继承 str
- >>> class CapStr(str):
- # 我们重写了 init 方法, 并且没有让用户提供任何参数
- def __init__(self):
- pass
- # 我们重写 new 方法, 但是他需要接受一个 string 参数.
- def __new__(cls,string):
- string = string.upper()
- return str.__new__(cls,string)
- # 我们在初始化的时候没有提供 string 参数, 这个时候会抛出异常
- >>> c = CapStr()
- Traceback (most recent call last):
- File "<pyshell#26>", line 1, in <module>
- c = CapStr()
- # 在 new 的时候缺失一个参数
- TypeError: __new__() missing 1 required positional argument: 'string'
- # 如果我们认为它初始化的时候会给初始值,
- >>> c = CapStr("i love you")
- Traceback (most recent call last):
- File "<pyshell#18>", line 1, in <module>
- c = CapStr("i love you")
- # 提示我们 Init 时候只有一个值, 其实就是默认的 self 值, 但是我们提供了两个
- TypeError: __init__() takes 1 positional argument but 2 were given
- #---------------------------------
- # 这个例子, 我们没有重写 init 方法
- >>> class CapStr(str):
- def __new__(cls,string):
- string = string.upper() #全部大写
- #为了避免死循环
- return str.__new__(cls,string)
- >>> c = CapStr('I love you')
- >>> c
- 'I LOVE YOU'
在任何新式类的 new()方法, 不能调用自身的 new()来制造实例, 因为这会造成死循环. 因此必须避免类似以下的写法: 在 CapStr 中避免: return CapStr.new(cls, *args, **kwargs)或 return cls.new(cls, *args, **kwargs).
使用 object 或者没有血缘关系的新式类的 new()是安全的, 但是如果是在有继承关系的两个类之间, 应避免互调造成死循环, 例如:(CapStr)return Child.new(cls), (Child)return CapStr.new(cls).
当我们在创建一个新的实例的时候, 会自动调用 object.new(cls), 通常来说, 新式类开始实例化时, new()方法会返回 cls(cls 指代当前类)的实例, 然后该类的 init()方法作为构造方法会接收这个实例 (即 self) 作为自己的第一个参数, 然后依次传入 new ()方法中接收的位置参数和命名参数.
注意: 如果 new()没有返回 cls(即当前类)的实例, 那么当前类的 init()方法是不会被调用 的. 如果 new()返回其他类 (新式类或经典类均可) 的实例, 那么只会调用被返回的那个类的构造方法.
- # 正常情况下
- >>> class C(object):
- def __new__(cls):
- return object.__new__(cls)
- def __init__(self):
- print("初始化 C")
- # 初始化的时候会调用自己的 init 方法
- >>> c = C()
初始化 C
- # 当打印 c 的时候我们看到内存空间是指向 C 的
- >>> c
- <__main__.C object at 0x0000000002E9C6D8>
- >>>
- # 异常情况
- # 创建一个 A 类
- >>> class A(object):
- def __init__(self):
- print("进入 A init")
- print("出去 A init")
- # 创建一个 B 类
- >>> class B(object):
- def __new__(cls):
- return object.__new__(A) #返回的时候指向 A 类的 init
- def __init__(self):
- print("进入 B init")
- print("出去 B init")
- # 初始化 B 类的实例这个时候我们看一下是否进去了 B 类的 init 方法
- >>> b = B()
- >>> b
- # 从答案中我们看到, 其实它的内存指向的是 A
- <__main__.A object at 0x0000000002E9CB70>
因此可以这么描述 new()和 ini()的区别, 在新式类中 new()才是真正的实例化方法, 为类提供外壳制造出实例框架, 然后调用该框架内的构造方法 init()使其丰满.
如果以建房子做比喻, new()方法负责开发地皮, 打下地基, 并将原料存放在工地. 而 init()方法负责从工地取材料建造出地皮开发招标书中规定的大楼, init()负责大楼的细节设计, 建造, 装修使其可交付给客户.
init, 就不介绍了, 之前的博客一直在用, 它就是构造方法 (函数), 当我们在实际开发过程中有需要在初始化实例的时候就需要赋值(set) 或者获取属性值 (get) 的行为, 那么可以通过该方法来进行完成.
__del__(self)它是 python 中的析构函数, 当使用 del 删除对象时, 会调用他本身的析构函数, 另外当对象在某个作用域中调用完毕, 在跳出其作用域的同时析构函数也会被调用一次, 这样可以用来释放内存空间.
__del__()也是可选的, 如果不提供, 则 Python 会在后台提供默认析构函数(垃圾回收机制)
如果要显式的调用析构函数, 可以使用 del 关键字, 方式如下: del 对象名
---------------------------------------------------------------------------------------------------------
垃圾回收机制:
Python 采用垃圾回收机制来清理不再使用的对象; Python 提供 gc 模块释放
不再使用的对象, Python 采用'引用计数' 的算法方式来处理回收,
即: 当某个对象在其作用域内不再被其他对象引用的时候, Python 就自动清除对象;
Python 的函数 collect()可以一次性收集所有待处理的对象(gc.collect())
- ----------------------------------------------------------------------------------------------------------
- >>> class C(object):
- def __init__(self):
- print("调用了 init 方法")
- def __del__(self):
- print("调用了 del 方法")
- # 实例化 C
- >>> c = C()
调用了 init 方法
- # 将 c 赋值给 c1, 也就是将 c 的指针地址给 c1, 这个时候指针是两份
- >>> c1 = c
- # 又开辟了一个地址, 存放指针
- >>> c2 = C()
调用了 init 方法
- >>> c3 = c2
- # 第一次删除的时候是不会调用 del 方法的, 因为还有一个指针指向它
- >>> del c
- # 删除了仅有的指针
- >>> del c1
调用了 del 方法
>>>
来源: http://www.bubuko.com/infodetail-2551511.html