Python中的__new__()方法的使用

__new__() 函数只能用于从object继承的新式类。

 

先看下object类中对__new__()方法的定义:

class object:
  @staticmethod # known case of __new__
  def __new__(cls*more): # known special case of object.__new__
    """ T.__new__(S, ...) -> a new object with type S, a subtype of T """
    pass

object将__new__()方法定义为静态方法,并且至少需要传递一个参数cls,cls表示需要实例化的类,此参数在实例化时由Python解释器自动提供。

我们来看下下面类中对__new__()方法的实现:

class Demo(object):
  def __init__(self):
    print '__init__() called...'
  def __new__(cls*args, **kwargs):
    print '__new__() - {cls}'.format(cls=cls
    return object.__new__(cls*args, **kwargs)
if __name__ == '__main__':
  de = Demo()


输出:

发现实例化对象的时候,调用__init__()初始化之前,先调用了__new__()方法

__new__()必须要有返回值,返回实例化出来的实例,需要注意的是,可以return父类__new__()出来的实例,也可以直接将object的__new__()出来的实例返回。

__init__()有一个参数self,该self参数就是__new__()返回的实例,__init__()在__new__()的基础上可以完成一些其它初始化的动作,__init__()不需要返回值。

若__new__()没有正确返回当前类cls的实例,那__init__()将不会被调用,即使是父类的实例也不行。

我们可以将类比作制造商,__new__()方法就是前期的原材料购买环节,__init__()方法就是在有原材料的基础上,加工,初始化商品环节。

实际应用过程中,我们可以这么使用:

class LxmlDocument(object_ref):
  cache = weakref.WeakKeyDictionary()
  __slots__ = ['__weakref__']
  def __new__(cls, response, parser=etree.HTMLParser):
    cache = cls.cache.setdefault(response, {})
    if parser not in cache:
      obj = object_ref.__new__(cls)
      cache[parser] = _factory(response, parser)
    return cache[parser]

该类中的__new__()方法的使用,就是再进行初始化之前,检查缓存中是否存在该对象,如果存在则将缓存存放对象直接返回,如果不存在,则将对象放至缓存中,供下次使用。

 

再来个单例的,通过重载__new__实现单例:

class Singleton(object):def __new__(cls, *args, **kwargs):if not hasattr(cls, '_instance'):cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)return cls._instanc

一、__init__ 方法是什么?

使用Python写过面向对象的代码的同学,可能对 __init__ 方法已经非常熟悉了,__init__ 方法通常用在初始化一个类实例的时候。例如:

 

 

这样便是__init__最普通的用法了。但__init__其实不是实例化一个类的时候第一个被调用 的方法。当使用 Persion(name, age) 这样的表达式来实例化一个类时,最先被调用的方法 其实是 __new__ 方法。

二、__new__ 方法是什么?

__new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。

 

 

执行结果:

 

 

通过运行这段代码,我们可以看到,__new__方法的调用是发生在__init__之前的。其实当 你实例化一个类的时候,具体的执行逻辑是这样的:

1. p = Person(name, age)

2. 首先执行使用name和age参数来执行Person类的__new__方法,这个__new__方法会 返回Person类的一个实例(通常情况下是使用 super(Persion, cls).__new__(cls, ... ...) 这样的方式),

3. 然后利用这个实例来调用类的__init__方法,上一步里面__new__产生的实例也就是 __init__里面的的 self

所以,__init__ 和 __new__ 最主要的区别在于:

1.__init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。

2.__new__ 通常用于控制生成一个新实例的过程。它是类级别的方法。

但是说了这么多,__new__最通常的用法是什么呢,我们什么时候需要__new__?

三、__new__ 的作用

依照Python官方文档的说法,__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass。

首先我们来看一下第一个功能,具体我们可以用int来作为一个例子:

假如我们需要一个永远都是正数的整数类型,通过集成int,我们可能会写出这样的代码。

 

 

但运行后会发现,结果根本不是我们想的那样,我们任然得到了-3。这是因为对于int这种 不可变的对象,我们只有重载它的__new__方法才能起到自定义的作用。

这是修改后的代码:

 

 

通过重载__new__方法,我们实现了需要的功能。

另外一个作用,关于自定义metaclass。其实我最早接触__new__的时候,就是因为需要自定义 metaclass,但鉴于篇幅原因,我们下次再来讲python中的metaclass和__new__的关系。

四、用__new__来实现单例

事实上,当我们理解了__new__方法后,我们还可以利用它来做一些其他有趣的事情,比如实现 设计模式中的 单例模式(singleton) 。

因为类每一次实例化后产生的过程都是通过__new__来控制的,所以通过重载__new__方法,我们 可以很简单的实现单例模式。

 

 

输出结果:

转载于:https://www.cnblogs.com/erhu/p/9567302.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367532.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是消息中间件

面向消息的中间件:Message-oriented Middleware, MOM 基本功能: 将信息以消息的形式,从一个应用程序传送到另一个或多个应用程序 主要特点: 消息异步接受,类似手机短信的行为,消息发送者不需要等待消息接受…

用Java分割大型XML文件

上周,我被要求用Java编写一些东西,该东西能够将单个30GB XML文件拆分为可配置文件大小的较小部分。 该文件的使用者将是一个中间件应用程序,该应用程序存在XML较大的问题。 在后台,它使用某种DOM解析技术,使它在一段时…

am82.top 1.php,Droppy v2.1.3 – PHP在线网盘系统

更新跨度比较大从1.4.6-2.1.3的更新日志我都贴出来利V2.1.9 (10 July, 2019)- Added option to define maximum upload chunk size in the admin panel- Fixed an issue where downloads were corruptedV2.1.8 (10 July, 2019)- Fixed an issue where upload password field wa…

抛出异常–缓慢而丑陋

这篇文章是关于历史经验以及最近应用的性能优化技术的。 几年前,我在特定的应用程序中发誓,我不得不发现隐藏在真正聪明的工程“技术”之下的无证行为。 它是一个典型的用于发票的单片Java EE应用程序。 最好忘记确切的代码,但是我记得开发人…

信号与线性系统翻转课堂笔记9——傅里叶变换概念

信号与线性系统翻转课堂笔记9——傅里叶变换 The Flipped Classroom9 of Signals and Linear Systems 对应教材:《信号与线性系统分析(第五版)》高等教育出版社,吴大正著 一、要点 (1,重点)…

abstract修饰符

1、一个类不能同时被 abstract 和 final 修饰。 2、如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。 3、抽象类可以包含抽象方法和非抽象方法。 4、抽象方法是由子类来实现。 5、抽象方法不能被声明成 final 和 static。 6、任…

埃及分数问题(带乐观估计函数的迭代加深搜索算法-IDA*)

#10022. 「一本通 1.3 练习 1」埃及分数 【题目描述】 在古埃及,人们使用单位分数的和(形如 $\dfrac{1}{a}​$​​ 的,$a$ 是自然数)表示一切有理数。如:$\dfrac{2}{3} \dfrac{1}{2} \dfrac{1}{6}​$​​&#xff0c…

玩转Jquery中的动画效果(animate方法)

jQuery 动画 - animate() 方法jQuery animate() 方法用于创建自定义动画。语法:$(selector).animate({params},speed,callback);必需的 params 参数定义形成动画的 CSS 属性。可选的 speed 参数规定效果的时长。它可以取以下值:"slow"、"…

matlab 等分矩阵,用matlab根据列拆分矩阵.

使用logical indexingBA(A(:,end)10,:);CA(A(:,end)2,:);回报>> BB 1 4 2 5 102 1 5 6 10>> CC 2 4 5 6 22 3 5 4 2编辑:在回复丹的评论这里是一般情况的扩展e unique(A(:,end));B cell(size(e));for k 1:numel(e)B{k} A(A(:,end)e(k),:);end或者更…

点击网页跟踪php代码的工具,使用ltrace工具跟踪PHP库函数调用的方法

本文实例讲述了使用ltrace工具跟踪PHP库函数调用的方法。分享给大家供大家参考,具体如下:可能大家已经很熟悉使用strace来跟踪系统调用,今天介绍一个跟踪库函数的利器ltrace比如我有这么一段PHP代码test.php:$y 1380;$arr array…

HDU 2841 Visible Trees(容斥)题解

题意:有一块(1,1)到(m,n)的地,从(0,0)看能看到几块(如果两块地到看的地方三点一线,后面的地都看不到)。 思路:…

Jquery获取服务器端控件ID的方法

<asp:textbox runat"server" id"txtMessage" textmode"SingleLine">some strings here...</asp:textbox>但是当这段代码输出到客户端时就变成了这样&#xff1a;<input name"ctl00$txtMessage" id"ctl00_txtMessa…

安全地创建和存储密码

几乎每次涉及用户配置文件时&#xff0c;都必须管理用户凭据&#xff0c;从而能够创建和存储用户密码。 通常应该使用散列密码和盐分密码来准备数据库公开和通过使用Rainbow表进行散列反转的密码。 但是&#xff0c;找到以明文形式存储的密码并不少见&#xff08;很不幸&#…

Swift Defer 延迟调用

1、Defer 在一些语言中&#xff0c;有 try/finally 这样的控制语句&#xff0c;比如 Java。这种语句可以让我们在 finally 代码块中执行必须要执行的代码&#xff0c;不管之前怎样的兴风作浪。在 Swift 2.0 中&#xff0c;Apple 提供了 defer 关键字&#xff0c;让我们可以实现…

mysql strtok,strtok()和strtok_r()

下面的说明摘自于最新的Linux内核2.6.29&#xff0c;说明了strtok()这个函数已经不再使用&#xff0c;由速度更快的strsep()代替/** linux/lib/string.c** Copyright (C) 1991, 1992 Linus Torvalds*//** stupid library routines.. The optimized versions should generally b…

from 下拉框多个值提交_Git commit 多行信息提交

git commit可接受多个消息标志(-m)来允许多行提交原文地址&#xff1a;https://www.stefanjudis.com/today-i-learned/git-commit-accepts-several-message-flags-m-to-allow-multiline-commits/原文作者&#xff1a;Stephan Schneider在命令行上使用git时&#xff0c;您可能已…

处理缓慢的资源泄漏

使用Java监视器查找资源泄漏 查找缓慢的资源泄漏是使应用程序服务器长时间保持正常运行的关键。 在这里&#xff0c;我解释了如何使用Java监视器来发现缓慢的资源泄漏&#xff0c;以及如何验证它们是实际的泄漏&#xff0c;而不仅仅是额外的预分配到某些HTTP连接器或数据库池中…

jquery简单实现点击弹出层效果实例

先看效果图&#xff1a;完整例子&#xff1a; <!-- 渐变弹出层 --><div id"race"><a href"#">点击</a></div><div id"racePop" class"raceShow">这里是弹出层效果</div> <script type&q…

Openfire源码阅读(一)

本篇先分析openfire源码的主要流程&#xff0c;模块细节后续再继续分析&#xff1b; 一、简介&#xff1a; Openfire是开源的实时协作服务器&#xff08;RTC&#xff09;&#xff0c;它是基于公开协议XMPP&#xff08;RFC-3920&#xff09;&#xff0c;并在此基础上实现了XMPP-…

常见的linux命令及其翻译

常见的linux指令 1、ls ll 查看文件信息 2、cd 切换工作目录 cd 或 cd ~ 切换到/home/用户目录 cd. 切换到当前目录 cd.. 切换到上级目录 cd- 切换入上次所在的目录 3、clear 或 ctrl l 清屏 4、pwd 显示当前路径 5、mkdir 创建目录 6、rm 删除文件 rm -r 删除文件夹 7、cp 拷…