__init__ vs __new__-何时使用以及如何使用
#编程 #教程 #python #oop

您必须在任何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__方法的参数。

Understanding *args & **kwargs in Python: Best Practices and Guide - GeekPython

当我们看到包含 *args和** kwargs的任何函数的文档时,您是否想知道这些奇怪的参数是什么

favicon geekpython.in

示例

# 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()函数。

How To Use super() Function Within Python Classes - GeekPython

您可能已经听到了以对象为导向的编程中的继承词,如果您没有的话,请不要担心,因为我们已经退缩了。

favicon geekpython.in

然后调用__init__方法,将实例传递给self参数。

然后我们打电话给Name类(Name()),当我们运行代码时,我们将获得下面显示的输出。

Called the __new__ method.
Called the __init__ method.

输出表明__new__方法首先调用,然后称为__init__方法。

__init__方法

正如我们在上面示例中看到的那样,__init__方法在创建对象后立即初始化对象的属性。

__init__ and __call__ In Python - What Do They Do? - GeekPython

您可能已经遇到了Python中的方法,这些方法具有前缀并带有双重下调的后缀,这些方法称为“ dunder方法”。

favicon geekpython.in

语法

__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_objname属性(实例变量)被初始化为'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上使用点表示法访问对象langyear的属性,就像我们在上述代码中所做的那样。

每次创建一个新对象时,都会调用__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

,则返回现有实例。

然后,我们打印了名为obj1obj2obj3Singleton类的三个实例,并检查了它们是否都一样。

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__方法,该方法分别接受langyear参数,分别具有"Python"1991的默认值。

当我们在没有参数的情况下调用Language类时,__init__方法将将langyear属性设置为默认值。

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


这就是目前的全部

保持编码