【Python之理解__new__和__init__的区别】

2024-01-30 14:29:36 浏览数 (2)

前言:

在 Python 的丰富工具箱中,_newinit 是两个看似相似却又截然不同的概念。这两个方法在对象的创建和初始化过程中扮演着关键的角色,理解它们之间的区别对于深入掌握 Python 的面向对象编程至关重要。从表面上看,它们都与对象的构建有关,但它们的职责和执行时机却有着根本性的不同。在本文中,我们将深入剖析 newinit,揭示它们各自的独特之处,带你走进 Python 对象创建的内部机制。

很多同学都以为Python中的__init__是构造方法,但其实不然,Python中真正的构造方法是__new__。__init__和__new__有什么区别?本文就来探讨一下。

我们先来看一下__init__的用法

代码语言:javascript复制
class Person(object):
    def __init__(self, name, age):
        print("in __init__")
        self._name = name
        self._age = age 

p = Person("Wang", 33) 

上面的代码会输出如下的结果

代码语言:javascript复制
in __init__
<__main__.Person object at 0x7fb2e0936450>

那么我们思考一个问题,Python中要实现Singleton怎么实现,要实现工厂模式怎么实现? 用__init__函数似乎没法做到呢~ 实际上,__init__函数并不是真正意义上的构造函数,__init__方法做的事情是在对象创建好之后初始化变量。真正创建实例的是__new__方法。 我们来看下面的例子

代码语言:javascript复制
class Person(object):
    def __new__(cls, *args, **kwargs):
        print("in __new__")
        instance = object.__new__(cls, *args, **kwargs)
        return instance

    def __init__(self, name, age):
        print("in __init__")
        self._name = name
        self._age = age

p = Person("Wang", 33)

上面的代码输出如下的结果

代码语言:javascript复制
in __new__
in __init__

上面的代码中实例化了一个Person对象,可以看到__new__和__init__都被调用了。__new__方法用于创建对象并返回对象,当返回对象时会自动调用__init__方法进行初始化。__new__方法是静态方法,而__init__是实例方法。 好了,理解__new__和__init__的区别后,我们再来看一下前面提出的问题,用Python怎么实现Singleton,怎么实现工厂模式? 先来看Singleton

代码语言:javascript复制
class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = object.__new__(cls, *args, **kwargs)

        return cls._instance

s1 = Singleton()
s2 = Singleton()
print(s1)
print(s2) 

上面的代码输出

代码语言:javascript复制
<__main__.Singleton object at 0x7fdef58b1190>
<__main__.Singleton object at 0x7fdef58b1190>

可以看到s1和s2都指向同一个对象,实现了单例模式。

再来看下工厂模式的实现

代码语言:javascript复制
class Fruit(object):
    def __init__(self):
        pass

    def print_color(self):
        pass

class Apple(Fruit):
    def __init__(self):
        pass

    def print_color(self):
        print("apple is in red")

class Orange(Fruit):
    def __init__(self):
        pass

    def print_color(self):
        print("orange is in orange")

class FruitFactory(object):
    fruits = {"apple": Apple, "orange": Orange}

    def __new__(cls, name):
        if name in cls.fruits.keys():
            return cls.fruits[name]()
        else:
            return Fruit()

fruit1 = FruitFactory("apple")
fruit2 = FruitFactory("orange")
fruit1.print_color()    
fruit2.print_color()    

上面的代码输出

代码语言:javascript复制
apple is in red
orange is in orange

动态创建类与 new

在 Python 中,我们经常需要在运行时动态地创建类,这时 new 方法可以发挥关键作用。通过在 new 中实现特定的逻辑,我们可以动态地配置类的属性、方法,甚至可以根据运行时的条件生成不同的类。这种灵活性为我们提供了在程序执行过程中根据需要自定义类的能力。

代码语言:javascript复制
class DynamicClassCreator:
    def __new__(cls, class_name, base_class, attributes):
        # 创建新的类
        new_class = super().__new__(cls)

        # 动态设置类名
        new_class.__name__ = class_name

        # 继承特定的基类
        new_class.__bases__ = (base_class,)

        # 动态添加属性和方法
        for attr_name, attr_value in attributes.items():
            setattr(new_class, attr_name, attr_value)

        return new_class

# 使用 __new__ 动态创建类
MyDynamicClass = DynamicClassCreator('MyDynamicClass', object, {'dynamic_method': lambda self: print("Dynamic Method")})

# 创建类的实例并调用动态添加的方法
instance = MyDynamicClass()
instance.dynamic_method()  # 输出: Dynamic Method

这个例子演示了如何使用 new 在运行时动态创建类,并设置类的名称、基类以及动态添加属性和方法。

继承与 newinit

在面向对象编程中,继承是一个强大的机制,而 newinit 方法在继承中起着至关重要的作用。当子类继承父类时,这两个方法是如何被继承和重写的呢?

首先,子类可以通过覆盖 new 方法来改变实例的创建方式。这意味着子类可以决定是否使用父类的实例创建逻辑,或者完全自定义自己的创建逻辑。这为子类提供了更灵活的控制权。

其次,子类可以通过覆盖 init 方法来添加或修改实例的初始化逻辑。这使得子类可以在初始化过程中执行额外的操作,而无需完全重写整个 new 方法。

代码语言:javascript复制
class ParentClass:
    def __new__(cls, *args, **kwargs):
        print("Creating an instance of ParentClass")
        instance = super().__new__(cls)
        return instance

    def __init__(self, name):
        print("Initializing ParentClass")
        self.name = name

class ChildClass(ParentClass):
    def __new__(cls, *args, **kwargs):
        print("Creating an instance of ChildClass")
        instance = super().__new__(cls)
        return instance

    def __init__(self, name, age):
        super().__init__(name)
        print("Initializing ChildClass")
        self.age = age

# 创建子类的实例
child_instance = ChildClass("John", 25)

这个例子演示了当子类继承父类时,newinit 方法是如何被继承和调用的。子类可以在这两个方法中添加自己的逻辑,同时保留对父类逻辑的调用。

这样的继承机制使得代码更加模块化,子类可以专注于自己的特定逻辑,而不必重复实现父类的大部分功能。

结尾:

通过本文的学习,我们深入了解了 Python 中 newinit 的差异,了解了它们在对象创建和初始化过程中的独特作用。new 负责对象的创建,而 init 负责对象的初始化。这两者协同工作,为我们提供了更灵活、更强大的对象创建和定制选项。在你的 Python 编程旅程中,掌握这两者的不同之处将使你更加游刃有余地处理复杂的对象创建过程,为你的代码增色不少。希望这篇文章带给你更清晰的认识,促使你在编写更高效、更具可维护性的 Python 代码时更加得心应手。

0 人点赞