python __new__方法解析和应用与单类

1、什么是__new__方法

__new__()是在新式类中新出现的方法,它作用在构造方法建造实例之前
可以这么理解,在Python 中 存在于类里面的构造方法
__init__()负责将类的实例化,而在__init__()启动之前,__new__()决定是否 要使用该__init__()方法
因为__new__()可以调用其他类的构造方法或者直接返回别的对象来作为本类 的实例。 如果将类比喻成工厂,那么__init__()方法就是该工厂的工人
__init__()方法接受的初始化参数就是生产所需的原料
_init__()方法会按照方法中的语句负责将原料加工成实例,以供工厂出货。
__new__()方法则是生产部经理
__new__方法可以决定是否将原料提供给该生产部工人
同时它还决定着出货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。

2、__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)

3、注意:


事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时
Python默认是调用该类的直接父类的__new__()方法来构造该类的实例
如果该类的父类也没有重写 __new__(),那么将一直按此规矩追溯至object的__new__()方法
因为object是所有新式类的基类。
__new__方法接受的参数虽然也是和__init__一样
但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法
新式类必定都有__new__(),因为所有新式类都是object的后代,而经典类则没有__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

通过运行这段代码,我们可以看到,__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__ 通常用于控制生成一个新实例的过程。它是类级别的方法

4、用__new__方法实现单类

# coding:utf8
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

4、实现数据库单类

# coding=utf-8
import MySQLdb

dbinfo = {"host": "192.168.1.89",
          "user": 'xxxx',
          "passwd": 'xxxx',
          "db": 'xxxx',
          "port": xxxx,
          "charset": "utf8",
          }


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


class Myclass(Single):
    def __init__(self):
        self.conn = None

    def connect(self):
        if self.conn is None:
            self.conn = MySQLdb.connect(**dbinfo)
            self.cur = self.conn.cursor()
        return self.conn, self.cur


D1 = Myclass()
D2 = Myclass()
d1 = D1.connect()
d2 = D2.connect()
print d1
print d2

输出结果为

(<_mysql.connection open to '192.168.1.89' at 293c2a8>, <MySQLdb.cursors.Cursor object at 0x00000000029D3C50>)
(<_mysql.connection open to '192.168.1.89' at 293c2a8>, <MySQLdb.cursors.Cursor object at 0x00000000029D3C50>)

可以看到D1,D2为同一个实例

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值