设为首页 收藏本站
查看: 4036|回复: 0

[经验分享] 实例解析Python中的__new__特殊方法

[复制链接]

尚未签到

发表于 2018-8-15 07:15:24 | 显示全部楼层 |阅读模式
  转载自:http://www.iyunv.net/article/85724.htm
  __new__方法在Python中用于被创建类实例,接下来我们以实例解析Python中的__new__特殊方法,注意一下__new__与__init__方法的区别
  __new__ 方法是什么?
  如果将类比喻为工厂,那么__init__()方法则是该工厂的生产工人,__init__()方法接受的初始化参 数则是生产所需原料,__init__()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而 __new__()则是生产部经理,__new__()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出 货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。
  __new__()方法的特性:
  1.__new__()方法是在类准备将自身实例化时调用。
  2.__new__()方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
  类的实例化和它的构造方法通常都是这个样子:
  class MyClass(object):
  def __init__(self, *args, **kwargs):
  ...
  # 实例化
  myclass = MyClass(*args, **kwargs)
  正如以上所示,一个类可以有多个位置参数和多个命名参数,而在实例化开始之后,在调用 __init__()方法之前,Python首先调用__new__()方法:
  def __new__(cls, *args, **kwargs):
  ...
  第一个参数cls是当前正在实例化的类。
  如果要得到当前类的实例,应当在当前类中的__new__()方法语句中调用当前类的父类 的__new__()方法。
  例如,如果当前类是直接继承自object,那当前类的__new__()方法返回的对象应该为:
  def __new__(cls, *args, **kwargs):
  ...
  return object.__new__(cls)
  (注意:
  事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时 ,Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写 __new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。)
  __new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。
  # -*- coding: utf-8 -*-
  class Person(object):
  """Silly Person"""
  def __new__(cls, name, age):
  print '__new__ called.'
  return super(Person, cls).__new__(cls, name, age)
  def __init__(self, name, age):
  print '__init__ called.'
  self.name = name
  self.age = age
  def __str__(self):
  return '<Person: %s(%s)>' % (self.name, self.age)
  if __name__ == '__main__':
  piglei = Person('piglei', 24)
  print piglei
  执行结果:
  piglei@macbook-pro:blog$ python new_and_init.py
  __new__ called.
  __init__ called.
  <Person: piglei(24)>
  通过运行这段代码,我们可以看到,__new__方法的调用是发生在__init__之前的。其实当 你实例化一个类的时候,具体的执行逻辑是这样的:
  p = Person(name, age)
  首先执行使用name和age参数来执行Person类的__new__方法,这个__new__方法会 返回Person类的一个实例(通常情况下是使用 super(Persion, cls).__new__(cls, ... ...) 这样的方式),
  然后利用这个实例来调用类的__init__方法,上一步里面__new__产生的实例也就是 __init__里面的的 self
  所以,__init__ 和 __new__ 最主要的区别在于:
  __init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。
  __new__ 通常用于控制生成一个新实例的过程。它是类级别的方法。
  但是说了这么多,__new__最通常的用法是什么呢,我们什么时候需要__new__?
  __new__ 的作用
  依照Python官方文档的说法,__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass。
  首先我们来看一下第一个功能,具体我们可以用int来作为一个例子:
  假如我们需要一个永远都是正数的整数类型,通过集成int,我们可能会写出这样的代码。
  class PositiveInteger(int):
  def __init__(self, value):
  super(PositiveInteger, self).__init__(self, abs(value))
  i = PositiveInteger(-3)
  print i
  但运行后会发现,结果根本不是我们想的那样,我们任然得到了-3。这是因为对于int这种 不可变的对象,我们只有重载它的__new__方法才能起到自定义的作用。
  这是修改后的代码:
  class PositiveInteger(int):
  def __new__(cls, value):
  return super(PositiveInteger, cls).__new__(cls, abs(value))
  i = PositiveInteger(-3)
  print i
  通过重载__new__方法,我们实现了需要的功能。
  另外一个作用,关于自定义metaclass。其实我最早接触__new__的时候,就是因为需要自定义 metaclass,但鉴于篇幅原因,我们下次再来讲python中的metaclass和__new__的关系。
  用__new__来实现单例
  事实上,当我们理解了__new__方法后,我们还可以利用它来做一些其他有趣的事情,比如实现 设计模式中的 单例模式(singleton) 。
  因为类每一次实例化后产生的过程都是通过__new__来控制的,所以通过重载__new__方法,我们 可以很简单的实现单例模式。
  class Singleton(object):
  def __new__(cls):
  # 关键在于这,每一次实例化的时候,我们都只会返回这同一个instance对象
  if not hasattr(cls, 'instance'):
  cls.instance = super(Singleton, cls).__new__(cls)
  return cls.instance
  obj1 = Singleton()
  obj2 = Singleton()
  obj1.attr1 = 'value1'
  print obj1.attr1, obj2.attr1
  print obj1 is obj2
  输出结果:
  value1 value1
  True
  可以看到obj1和obj2是同一个实例。
  python单例模式实现的四种方法:http://blog.csdn.net/sirodeng/article/details/17426543

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-551889-1-1.html 上篇帖子: python的常见数据类型 下篇帖子: 用户登陆python脚本
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表