Python中new类方法和init 实例方法以及单例模式的介绍(附示例)

本篇文章给大家带来的内容是关于python中new类方法和init 实例方法以及单例模式的介绍(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

Python 中的类都是单例模式?” 一天,一同事问我这样一个问题。这是一个奇怪的问题,可能你也这么认为。这里先不做解释,我们先来看看 __new__ 和 __init__ 方法。

new 与 init

__new__ 方法属于新式类,即属于 object 类。它是一个静态方法,但是其第一个参数必须是一个类(cls),这有点像一个 classmethod,其实将其看成是一个类方法也可以。该特殊方法被调用时,会创建类(cls)的一个新实例并返回,实例被创建后解释器会将该实例以及其它的参数传递给该实例的初始化函数 __init__,以对实例进行初始化。

所以,__new__ 方法是一个类方法,用于创建一个实例,而 __init__ 方法是一个实例方法,用于初始化一个实例。

__new__ 方法在实例化一个类时被调用,重写该方法应该像如下的形式:

立即学习“Python免费学习笔记(深入)”;

class A(object):    def __new__(cls, *args, **kwargs)        return super(A, cls).__new__(cls, *args, **kwargs)

登录后复制

如果 __new__ 方法不返回 cls 的一个实例,那么新的实例的 __init__ 方法不会被调用。需要注意的是,在 Python 3.3 之后,new 方法不再接收额外的参数,否则会有异常 TypeError: object() takes no parameters。

__init__ 方法在实例被创建之后被调用,该方法仅仅是对 __new__ 方法创建的实例进行一些初始化操作。注意,如果 new 方法返回实例,则 init 方法总是会被调用(这一点在用 new 方法实现单例时要特别注意)

可以来做一下验证:

class Foo(object):    def __new__(cls, m, n):        print "__new__ is called"        return super(Foo, cls).__new__(cls, m, n)    def __init__(self, m, n):        print "__init__ is called"        self.m = m        self.n = n    def __repr__(self):        return "Foo(m={self.m}, n={self.n})".format(self=self)    def __str__(self):        return self.__repr__()if __name__ == "__main__":    f = Foo(1, 2)    print f

登录后复制

输出结果:

__new__ is called__init__ is calledFoo(m=1, n=2)

登录后复制

于是可以得出结论:

1、 __new__ 属于类级别的方法,即使没有被 classmethod 装饰,其决定生成实例的过程。

2、 __init__ 属于实例级别的方法,决定实例初始化的过程,比如添加属性,对初始化参数进行判断,转换等。

需要注意的是,在重写 __new__ 方法与 __init__ 方法的参数应该保持一致,否则会有 TypeError 发生。如果直接调用 object.__new__() 则在 Python 3.3 及以后的版本中不再支持传入参数,这一点参考自:https://stackoverflow.com/questions/34777773/typeerror…

__init__ 方法,在定义一个 class 的时候一般都会涉及到,也是比较常用。而 __new__ 方法则很少会用到,那么它到底有什么用途呢?

new 方法作用

__new__ 方法比较常用的作用大概是:

1、 继承内建不可变类型时(比如int, str, tuple),提供自定义实例化过程。因为如果在 __init__ 方法中做都写操作可能会无效。例如:

class CustomInt(int):    def __init__(self, v):        super(CustomInt, self).__init__(self, abs(v))print CustomInt(-1)# 输出:-1

登录后复制

这可能没有达到期望的效果。但可以通过重写 __new__ 方法来实现:

class CustomInt(int):    def __new__(cls, v):        return super(CustomInt, cls).__new__(cls, abs(v))print CustomInt(-1)# 输出:1

登录后复制

2、 实现自定义的元类(metaclass)。元类就是用来定义如何创建类,它的概念可能稍微复杂些,这里不做详细讨论。

3、 实现单例。由于类产生实例的过程是通过 __new__ 方法来控制的,因此重写该方法来单例模式是非常方便的:

class Singleton(object):    def __new__(cls):        if not hasattr(cls, "_instance"):            cls._instance = super(Singleton, cls).__new__(cls)        return cls._instanceassert Singleton() is Singleton()  # 断言成功

登录后复制

所谓单例模式就是每次初始化都返回同一个实例,所以两次初始化得到的对象的内存地址应该是一样的:

print Singleton(), Singleton()

登录后复制

结果应该是显而易见的:

 

登录后复制

装饰器实现单例

说到单例模式,除了用 __new__ 方法实现外,还有一些其他的方式,如装饰器、元类等。不同方式的实现有不同的作用,元类属于 Python 中更为高级的特性,本文不做讨论,我们来看一下用装饰器实现单例的方法。

装饰器(decorator)可以动态地修改一个类或函数的功能,即类也可以被装饰器装饰。因此可以使用装饰器来装饰某个类,使其被初始化时只生成一个实例:

from functools import wrapsdef singleton(cls):    instances = {}    @wraps(cls)    def getinstance(*args, **kwargs):        if cls not in instances:            instances[cls] = cls(*args, **kwargs)        return instances[cls]    return getinstance@singletonclass MyClass(object):    def __init__(self):        pass

登录后复制

需要注意的是,使用装饰器实现单例时,类已经变成了一个函数,而不再是类。 如上用上例中 MyClass 初始化实例时,实际上调用的是被装饰后返回的 getinstance 函数。

用 __new__ 实现单例和用装饰实现单例的区别是,前者前者都是会调用 __init__ 方法,这就意味着每次初始化时用不同的参数,虽然返回的实例时同一个,但是实例的属性却被重新设置了;而后者则总是返回第一次初始化创建的示例和设置的属性,即使后面传入了不同的参数。

奇怪现象

接着,我们再来看一个 “奇怪” 的现象:

>>> class A(object):...     pass...>>> print A(), A() >>> print A(), A() >>> print A(), A() 

登录后复制

是不是感觉有些难以置信,print 语句后两次创建的对象应该是不一样的,而他们却莫名奇妙的一样。这就是我讨论本文内容的原因。

一次同事问我,Python 中的类都是单例模式?我当时一脸懵逼,听了他的描述,我自己也试了下,果然存在如上所示的“奇怪”现象。于是我就去了解了 Python 单例模式的实现,在了解到 __new__ 的实现方式时,就想对 __new__ 和 __init__ 有一个更加深入的了解。于是就有了本文所讨论的内容。

然后,我想着用 is 来判断下他们是否真的是同一个实例:

>>> A() is A()False

登录后复制

我没有对 CPython 的源码进行过全面的阅读,所以对其很多内部的实现机制不是太了解。我猜 Python 解释器在内部可能做了优化,像 print A(), A() 这样的语句,解释器认为没有必要创建不同的对象,直接返回同一个实例的引用得了。是不是觉得解释器有些自作聪明!而当 A() is A() 这样的表达式出现时,解释器想,我不能再自作聪明,那样可能会误导别人。可是,在 print 语句那样的用法时,就已经误导我了,我都差点开始怀疑人生了!

从语法来看,大家应该知道,我在测试时使用的 Python 2。我后来也试了下 Python 3:

>>> class A():...     pass...>>> print(A(), A()) >>> print(A(), A()) >>> print(A(), A()) >>> A() is A()False

登录后复制

我想,这样的结果才是不会让人困惑的。可能是 Python 社区意识到了这个问题并在 Python3 中进行了修正。这样的修正是好的,否则对于像我同事那样初次使用 Python 的人来说是很困惑的。

个人认为,Python3 对过去的一些“错误”的修正是好的。例如将 print 改为函数,提供了丰富的参数来控制输出的样式;对编码的调整等等。

以上就是Python中new类方法和init 实例方法以及单例模式的介绍(附示例)的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2534067.html

(0)
上一篇 2025年3月5日 21:25:47
下一篇 2025年2月24日 21:31:56

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 怎么找到黑客的联系方式?

    如果你想要找到黑客的联系方式,那么你可能面临以下难题:黑客往往会隐藏他们的身份,并且他们的联系方式很难被发现。php小编草莓在这里为你提供了一份指南,旨在帮助你找到黑客的联系方式。在本指南中,我们将介绍一些常见的黑客使用的联系方式,并提供一…

    2025年3月5日
    200
  • Python中datetime模块的介绍(附示例)

    本篇文章给大家带来的内容是关于python中datetime模块的介绍(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 Python提供了多个内置模块用于操作日期时间,像 calendar,time,datetim…

    编程技术 2025年3月5日
    200
  • 为什么黑客都用python

    python支持功能强大的黑客攻击模块,而且python提供多种库,用于支持黑客攻击,python提供了ctypes库, 借助它, 黑客可以访问windows、os x、linux等系统提供 dll与共享库,还有python语言易学易用,这…

    2025年3月5日
    200
  • Tensorflow分类器项目自定义数据读入的方法介绍(代码示例)

    本篇文章给大家带来的内容是关于Tensorflow分类器项目自定义数据读入的方法介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 Tensorflow分类器项目自定义数据读入 在照着tensorflow官网的…

    2025年3月5日
    200
  • Python正则表达式和re库的相关内容介绍(代码示例)

    本篇文章给大家带来的内容是关于python正则表达式和re库的相关内容介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 正则表达式是定义搜索模式的字符序列。通常这种模式被字符串搜索算法用于字符串上的“查找”或…

    编程技术 2025年3月5日
    200
  • Python中浮点型的基本内容介绍(代码示例)

    本篇文章给大家带来的内容是关于python中浮点型的基本内容介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 1.浮点数的介绍 float(浮点型)是Python基本数据类型中的一种,Python的浮点数类似…

    编程技术 2025年3月5日
    200
  • Python中整型的基本介绍(代码示例)

    本篇文章给大家带来的内容是关于python中整型的基本介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 Python中有以下几个基本的数据类型: 整数 int 字符串 str 浮点数 float 立即学习“P…

    编程技术 2025年3月5日
    200
  • Python中的命名空间和范围

    在python中,每个包、模块、类、函数和方法函数都拥有一个“名称空间”,其中解析了变量名称。下面本篇文章就来带大家认识一下python中的命名空间和范围,希望对大家有所帮助。 什么是命名空间: 命名空间是一个系统,用于确保程序中的所有名称…

    2025年3月5日
    200
  • 如何使用Python压缩/解压缩zip文件?(代码示例)

    在批量交换大文件和多个文件时,使用zip文件是非常方便的。下面本篇文章就来带大家认识解一下zip文件,介绍使用python压缩或解压缩zip文件的方法,希望对大家有所帮助。【视频教程推荐:python教程】 什么是zip文件? zip文件是…

    2025年3月5日
    200
  • Python和Go之间的区别是什么?

    python和go都是用于编写web应用程序的强大的高级编程语言,它们之间有什么区别吗?下面本篇文章就来带大家认识一下python和go语言,简单比较一下python和go,让大家了解python和go之间的区别有哪些,希望对大家有所帮助。…

    2025年3月5日
    200

发表回复

登录后才能评论