您必须在任何Python类中看到__init__
方法的实现,如果您使用Python类工作,则必须多次实现__init__
方法。但是,您不太可能在任何类中实现或看到__new__
方法。
在本文中,我们将看到:
-
__init__
和__new__
方法的定义 -
__init__
方法和__new__
方法实现 -
应使用
-
两种方法之间的区别
__init__ vs __new__方法
__init__
方法是一种初始化方法,用于创建对象后初始化其属性,而__new__
方法用于创建对象。
当我们同时定义__new__
和__init__
方法时,python首先调用__new__
方法来创建对象,然后调用__init__
方法来初始化对象的属性。
大多数编程语言仅需要一个构造函数,一种创建和初始化对象的特殊方法,但是Python既具有构造函数又有一个初始化器。
让我们一一谈论这两种方法,并在Python类中实现这些方法。
__new__方法
已经说过,__new__
方法是一种构造方法,用于创建和返回对象(类的实例)。
语法
object.__new__(cls, *args, **kwargs)
__new__
方法的第一个参数是cls
,它是我们要创建的对象类别。
*args
和**kwargs
参数未由__new__
方法使用,但是它们必须匹配班级的__init__
方法的参数。
示例
# Defined a base class
class Name:
# Created a __new__ method
def __new__(cls):
print(f'Called the __new__ method.')
return super(Name, cls).__new__(cls)
# Created an __init__ method
def __init__(self):
print(f"Called the __init__ method.")
# Created an object
Name()
在上面的代码中,我们在类Name
中定义了__new__
和__init__
方法。 __new__
方法接受cls
参数,该参数用于参考类Name
,当调用时,它会打印消息并使用super(Name, cls).__new__(cls)
返回类实例。
要注意的一件事是,Name
类是基类,因此我们可以直接在对象上的__new__
方法(如此expression object.__new__(cls)
)上称为__new__
方法。但是,标准方法是使用super()
函数。
然后调用__init__
方法,将实例传递给self
参数。
然后我们打电话给Name
类(Name()
),当我们运行代码时,我们将获得下面显示的输出。
Called the __new__ method.
Called the __init__ method.
输出表明__new__
方法首先调用,然后称为__init__
方法。
__init__方法
正如我们在上面示例中看到的那样,__init__
方法在创建对象后立即初始化对象的属性。
语法
__init__(self, *args, **kwargs)
作为第一个参数,__init__
方法接受self
,该方法用于参考类实例。
参数*args
和**kwargs
用于初始化实例变量,其中存储在它们中的值。
示例
# Defined a base class
class Name:
# Created a __new__ method
def __new__(cls, name):
print(f'Called the __new__ method.')
return super(Name, cls).__new__(cls)
# Created an __init__ method
def __init__(self, name):
print(f"Called the __init__ method.")
self.name = name
# Created an object
name_obj = Name('Sachin')
print(name_obj.name)
在__init__
方法中,我们通过了name
参数,并在__new__
方法中使用了相同的操作,以使__new__
和__init__
方法signature彼此兼容。
我们使用'Sachin'
参数调用类,该参数将自动调用__init__
方法,并将以此值初始化实例变量self.name
。
当我们在对象name_obj
上调用name
属性(实例变量)时,我们将获得以下输出。
Called the __new__ method.
Called the __init__ method.
Sachin
name_obj
的name
属性(实例变量)被初始化为'Sachin'
。
实施
让我们在类Language
中同时定义__new__
和__init__
方法。
class Language:
def __new__(cls, *args):
return super().__new__(cls)
def __init__(self, lang, year):
self.lang = lang
self.year = year
language = Language('Python', 1991)
print(language.lang)
print(language.year)
----------
Python
1991
我们在类Language
中定义了__new__
和__init__
方法,并创建了类对象,当我们运行代码时,python将调用__new__
方法,该方法负责创建和返回类的对象,然后调用__init__
0负责对象属性初始化(实例变量)的方法。
现在,我们可以在对象language
上使用点表示法访问对象lang
和year
的属性,就像我们在上述代码中所做的那样。
每次创建一个新对象时,都会调用__init__
方法,这意味着,如果我们不返回super().__new__(cls)
,那么__init__
方法将不会执行并返回None
。
class Language:
def __new__(cls, *args):
print("Creating")
# Method not called
def __init__(self, lang, year):
print("Initializing")
self.lang = lang
self.year = year
language = Language('Python', 1991)
print(language)
----------
Creating
None
让我们看看当我们仅在类中实现 __init__
方法时会发生什么。
class Language:
def __init__(self, lang, year):
self.lang = lang
self.year = year
language = Language('Python', 1991)
print(language.lang)
print(language.year)
----------
Python
1991
该代码与我们在本节开头看到的先前代码相同。
当我们使用language = Language('Python', 1991)
实例化类时,该表达式等效于以下内容:
language = object.__new__(Language)
language.__init__('Python', 1991)
如果我们使用__dict__
调用__new__
和__init__
方法后尝试打印language
对象,那么我们将获得以下输出:
language = object.__new__(Language)
print(language.__dict__)
language.__init__('Python', 1991)
print(language.__dict__)
----------
{}
{'lang': 'Python', 'year': 1991}
调用__new__
方法后,我们得到了一个空词典,因为该对象是创建但尚未初始化的,为了初始化,我们明确调用了__init__
方法并获得了值。
何时使用
__new__的用例
考虑以下示例,我们使用__new__
方法在实例化下自定义对象。
class Reverse(str):
def __new__(cls, sequence):
return super().__new__(cls, sequence[::-1])
seq = Reverse("GeekPython")
print(seq)
以上代码定义了从str
内置类型继承的类Reverse
以及接受sequence
的__new__
方法。在创建对象之前
nohtyPkeeG
参数"GeekPython"
传递给Reverse
类在创建对象之前由于sequence[::-1]
而被逆转。
这不能使用__init__
方法完成,如果我们尝试这样做,结果将是一个错误。
class Reverse(str):
def __init__(self, sequence):
super().__init__(sequence[::-1])
seq = Reverse("GeekPython")
print(seq)
----------
TypeError: object.__init__() takes exactly one argument (the instance to initialize)
__new__
方法的另一种用例是创建一个Singleton (设计模式将类实例化限制为单个实例)。
class Singleton:
# Created a private variable
__ins = None
# Defined the __new__ method
def __new__(cls):
if cls.__ins is None:
print("Instance creating...")
cls.__ins = super().__new__(cls)
return cls.__ins
# Creating object
obj1 = Singleton()
obj2 = Singleton()
obj3 = Singleton()
print(obj1)
print(obj2)
print(obj3)
# Checking if they are all same
print(obj1 is obj2 is obj3)
在上面的代码中,我们定义了Singleton
类,并创建了一个私有变量__obj
来存储类的单个实例,以及一个检查__ins
是否为None
的__new__
方法,然后创建新实例并将其分配给__ins
,如果__ins
不是None
。
然后,我们打印了名为obj1
,obj2
和obj3
的Singleton
类的三个实例,并检查了它们是否都一样。
Instance creating...
<__main__.Singleton object at 0x000001B3DFD5C130>
<__main__.Singleton object at 0x000001B3DFD5C130>
<__main__.Singleton object at 0x000001B3DFD5C130>
True
所有三个实例都指向相同的内存地址,我们可以看到我们有True
,表明它们都是相同的。
__init __的用例
__init__
方法通常用于使用或不带有默认值的对象属性初始化对象的属性。
class Language:
def __init__(self, lang="Python", year=1991):
self.lang = lang
self.year = year
def show(self):
print(f'Language: {self.lang} | Founded: {self.year}.')
language = Language()
language.show()
以上代码定义了Language
类和__init__
方法,该方法分别接受lang
和year
参数,分别具有"Python"
和1991
的默认值。
当我们在没有参数的情况下调用Language
类时,__init__
方法将将lang
和year
属性设置为默认值。
Language: Python | Founded: 1991.
不同之处
现在我们已经看到了这两种方法的定义,语法和实现,我们现在能够区分它们。
__新方法 | __ init__方法 |
---|---|
__new__ 方法称为第一个 |
__init__ 方法是在__new__ 方法 | 之后调用的
用于创建和返回对象 | 用于初始化对象的属性 |
它是构造方法 | 这是一个初始化方法 |
将类作为第一个参数 | 将类的实例作为第一个参数 |
可以被覆盖以自定义实例化对象 | 可能仅用于初始化对象的属性 |
结论
Python具有构造函数和初始化方法的概念。 __new__
方法是一种构造方法方法,而__init__
方法是一种初始化方法。 Python首先调用负责对象创建的__new__
方法,然后调用负责对象属性初始化的__init__
方法。
如果您喜欢这个 ,您可能会感兴趣的其他文章
Context managers and the with statement in Python。
What is abstract base class(ABC) in Python?
Public, Protected, and Private access modifiers in Python。
What are inheritance and different types of inheritance in Python?
What is enumerate() function in Python?
Execute dynamically generated code using the exec() in Python。
Async/Await - Asynchronous programming using asyncio in Python。
这就是目前的全部
保持编码