Python每日一题:__new__ 与 __init__

时间:2022-07-23
本文章向大家介绍Python每日一题:__new__ 与 __init__,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目:Python 中__init__ 与 __new 的区别?

扩展:1.怎么理解 __new__?

2. Python 中怎么实现单例模式?

3. Python 中类的实例化是什么样的过程?

答案要点:

  1. __new__() 是一个静态方法,尽管并没有 @staticmethod 来修饰。它主要用于生成类的实例对象,所以当执行 a = A() 时,会首先执行 __new__()。这个方法是有返回值的,一般它的返回值是当前调用类的实例对象。它的定义如下:
# __new__ 的参数是 类,一旦这个方法创建过实例对象后就会调用 __init__()
object.__new__(cls[,...])
    pass

# 如果需要调用父类的 __new__
python2
super(子类名, cls).__new__(cls[,...])

python3
super().__new__(cls[,...])
  1. __init__ 是在实例对象被创建之后才被调用的,也就是在执行完 __new__ 之后。它的定义如下:
# 实例方法都会以 self 开头,这个 self 其实就是当前的实例对象
# 实例对象当然是要先创建的,既然在调用 __init__ 参数就已经是 self 了,
# 说明在这之前一定是有方法去生成实例对象的
object.__init__(self[,...])
    pass

# 如果需要调用父类的 __init__
python2
super(子类名, self).__init__([args...])

python3
super().__init__([args...])
  1. __init__ 返回值为 None,如果返回任意一个非 None 的值,会报 TypeError。示例如下:
class Test(object):
    def __init__(self):
        return "123"

t = Test() # TypeError: __init__() should return None, not 'str'
  1. __init__() 方法的作用很简单,和我们在 JAVA 中的构造方法是类似的,用来给实例属性赋值等操作。而按照官方文档的说法,对 __new()__ 的解释如下:

new() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation. 简单翻译: new() 主要用于允许对不可变类型,如 int, str, tuple ,来自定义如何创建他们的实例。它也可以用于在使用元类时重写,以便我们客制化类的创建

首先,我们来看下第一个作用,比如我们有一种需求,是一直要得到大写的字符串,类似新增一种数据类型,它会一直返回字符串的大写形式。我们就可以用 __new__ 来实现。示例如下:

class UpperStr(str):  # 继承 str
    def __new__(cls, value):  # 重写 __new__ 来拦截创建实例对象的过程
        # 在调用父类 __new__ 时,变成大写
        return super(UpperStr, cls).__new__(cls, str.upper(value))

#  单纯用 __init__() 是无法实现的
#    def __init(self, value):
#        return super(UpperStr, cls).__init__(str.upper(value))

s = UpperStr("abc")
print(s)  # ABC

其次第二个作用,就是我们通过使用元类来构造类时,可以通过重载元类的 __new__ 方法,修改 类定义 的行为。这个在后面专题讲 元类 时再详细介绍

  1. 除了上述作用,__new__ 还可以用于实现单例模式,原理也很简单,就是在创建实例对象时,先判断是否已经实例化。示例代码如下:
class MySingleton(object):
    def __new__(cls):
        if not hasattr(cls, 'instance'):
            cls.instance = super(MySingleton, cls).__new__(cls)


m1 = MySingleton()

m2 = MySingleton()

print(id(m1) == id(m2))  # 可以用 id() 来判断是否是同一个实例对象,但一般不常用

print(m1 is m2)  # 一般用 is 来判断 

愿关注我们的人都能找到

属于自己的皮球