如何理解Python中的__new__ 和__init__ 方法
__new__
和 __init__
是两个在类定义中经常遇到但作用完全不同的特殊方法(也称为魔术方法或双下划线方法),在讲解单例模式之前,必须先学习这块的知识
__new__ 的特点
- new 是一个静态方法(它默认接受 cls 作为第一个参数,代表当前类,此参数在实例化时由Python解释器自动提供),用于创建并返回类的实例。
- 在对象实例化过程中,new 方法首先被调用,然后才是 init 方法。
- 默认情况下,new 方法在 object 基类中定义,并返回 cls(即类本身)的一个新实例。但可以通过继承并重写这个方法来自定义实例的创建过程。
- new 方法必须返回一个类的实例(通常是当前类的实例,但也可以是其他类的实例),否则Python会引发 TypeError。
- 如果不需要改变实例的创建过程(比如实现单例模式),就不需要重写 new 方法。
__init__ 的特点
- init 是一个实例方法,用于初始化新创建的对象。
- 当 new 方法成功返回一个新的实例后,Python会自动调用这个实例的 init 方法(如果存在)。
- init 方法的主要作用是设置实例的初始状态或执行一些必要的设置。
- init 方法可以没有返回值(或显式返回 None),因为它不负责创建实例;实例的创建由 new 方法负责。
一句话简单概括:__new__方法创建并返回实例,__init__初始化实例
1、执行顺序,先执行__new__方法,再执行__init__方法
class MyClass:
def __init__(self):
print("__init__ running")
def __new__(cls):
print("__new__ running")
return super().__new__(cls)
instance= MyClass()
#__new__ running
#__init__ running
2、__new__方法构造一个类实例,并将该实例传递给自身的__init__()方法,即__init__()方法的self参数。
class MyClass:
def __new__(cls):
print("__new__ running")
instance = super().__new__(cls)
print(instance)
print(type(instance))
print(id(instance))
print("\n")
return instance
def __init__(self):
print("__init__ running")
print(self)
print(type(self))
print(id(self))
instance= MyClass()
# __new__ running
# <__main__.MyClass object at 0x000001C906EFCBB0>
# <class '__main__.MyClass'>
# 1962916432816
# __init__ running
# <__main__.MyClass object at 0x000001C906EFCBB0>
# <class '__main__.MyClass'>
# 1962916432816
3、__new__方法必须返回实例,否则__init__方法不被调用
class MyClass:
def __new__(cls):
print("__new__ running")
instance = super().__new__(cls)
# return instance
def __init__(self):
print("__init__ running")
instance= MyClass()
# __new__ running
4、如果重写__new__方法,除了cls参数外,还需保持和__init__的其他入参一致
class MyClass:
def __new__(cls):
print("__new__ running")
instance = super().__new__(cls)
return instance
def __init__(self,name,age):
print("__init__ running")
self.name =name
self.age = age
instance= MyClass('YANG',99)
#Traceback (most recent call last):
# File "xxx.py", line 14, in <module>
# instance= MyClass('YANG',99)
#TypeError: __new__() takes 1 positional argument but 3 were given
正确应该这样写:
class MyClass:
def __new__(cls,name,age):
print("__new__ running")
instance = super().__new__(cls)
return instance
def __init__(self,name,age):
print("__init__ running")
self.name =name
self.age = age
instance= MyClass('YANG',99)
或者,推荐这样写:
class MyClass:
def __new__(cls,*args,**kwargs):
print("__new__ running")
instance = super().__new__(cls)
return instance
def __init__(self,name,age):
print("__init__ running")
self.name =name
self.age = age
instance= MyClass('YANG',99)