详解python单例模式与metaclass

单例模式的实现方式

将类实例绑定到类变量上

class Singleton(object):
  _instance = None

  def __new__(cls, *args):
    if not isinstance(cls._instance, cls):
      cls._instance = super(Singleton, cls).__new__(cls, *args)
    return cls._instance

但是子类在继承后可以重写__new__以失去单例特性

class D(Singleton):

  def __new__(cls, *args):
    return super(D, cls).__new__(cls, *args)

使用装饰器实现

def singleton(_cls):
  inst = {}

  def getinstance(*args, **kwargs):
    if _cls not in inst:
      inst[_cls] = _cls(*args, **kwargs)
    return inst[_cls]
  return getinstance

@singleton
class MyClass(object):
  pass

问题是这样装饰以后返回的不是类而是函数,当然你可以singleton里定义一个类来解决问题,但这样就显得很麻烦了

使用__metaclass__,这个方式最推荐

class Singleton(type):
  _inst = {}

  def __call__(cls, *args, **kwargs):
    if cls not in cls._inst:
      cls._inst[cls] = super(Singleton, cls).__call__(*args)
    return cls._inst[cls]

class MyClass(object):
  __metaclass__ = Singleton

metaclass

元类就是用来创建类的东西,可以简单把元类称为“类工厂”,类是元类的实例。type就是Python的内建元类,type也是自己的元类,任何一个类

>>> type(MyClass)
type
>>> type(type)
type

python在创建类MyClass的过程中,会在类的定义中寻找__metaclass__,如果存在则用其创建类MyClass,否则使用内建的type来创建类。对于类有继承的情况,如果当前类没有找到,会继续在父类中寻找__metaclass__,直到所有父类中都没有找到才使用type创建类。
如果模块里有__metaclass__的全局变量的话,其中的类都将以其为元类,亲自试了,没这个作用,无任何影响

查看type的定义,

type(object) -> the object's type
type(name, bases, dict) -> a new type

所以利用type定义一个类的元类,可以用函数返回一个上面第二种定义的对象,也可以继承type并重写其中的方法。

直接使用type生成的对象作为元类,函数作用是使属性变为大写

def update_(name, bases, dct):
  attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
  uppercase_attr = {name.upper(): value for name, value in attrs}
  return type(name, bases, uppercase_attr)

class Singleton(object):
  __metaclass__ = update_
  abc = 2

d = Singleton()
print d.ABC
# 2

上一节中,单例模式元类实现用的是类继承方式,而对于第一种__new__的方式,本质上调用的是type.__new__,不过使用super能使继承更清晰一些并避免一些问题

这里简单说明一下,__new__是在__init__前调用的方法,会创建对象并返回,而__init__则是用传入的参数将对象初始化。看一下type中这两者以及__call__的实现

def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__
    """
    type(object) -> the object's type
    type(name, bases, dict) -> a new type
    # (copied from class doc)
    """
    pass

@staticmethod # known case of __new__
def __new__(S, *more): # real signature unknown; restored from __doc__
  """ T.__new__(S, ...) -> a new object with type S, a subtype of T """
  pass

def __call__(self, *more): # real signature unknown; restored from __doc__
  """ x.__call__(...) <==> x(...) """
  pass

前面提到类相当于元类的实例化,再联系创建单例模式时使用的函数,用的是__call__,其实用三种magic method中任何一种都是可以的,来看一下使用元类时各方法的调用情况

class Basic(type):
  def __new__(cls, name, bases, newattrs):
    print "new: %r %r %r %r" % (cls, name, bases, newattrs)
    return super(Basic, cls).__new__(cls, name, bases, newattrs)

  def __call__(self, *args):
    print "call: %r %r" % (self, args)
    return super(Basic, self).__call__(*args)

  def __init__(cls, name, bases, newattrs):
    print "init: %r %r %r %r" % (cls, name, bases, newattrs)
    super(Basic, cls).__init__(name, bases, dict)

class Foo:
  __metaclass__ = Basic

  def __init__(self, *args, **kw):
    print "init: %r %r %r" % (self, args, kw)

a = Foo('a')
b = Foo('b')

结果

new: <class '__main__.Basic'> 'Foo' () {'__module__': '__main__', '__metaclass__': <class '__main__.Basic'>, '__init__': <function init at 0x106fd5320>}
init: <class '__main__.Foo'> 'Foo' () {'__module__': '__main__', '__metaclass__': <class '__main__.Basic'>, '__init__': <function init at 0x106fd5320>}
call: <class '__main__.Foo'> ('a',)
init: <__main__.Foo object at 0x106fee990> ('a',) {}
call: <class '__main__.Foo'> ('b',)
init: <__main__.Foo object at 0x106feea50> ('b',) {}

元类的__init__和__new__只在创建类Foo调用了一次,而创建Foo的实例时,每次都会调用元类的__call__方法

以上就是本文的全部内容,对python单例模式与metaclass进行了描述,希望对大家的学习有所帮助。

(0)

相关推荐

  • Python探索之Metaclass初步了解

    先以一个大牛的一段关于Python Metapgramming的著名的话来做开头: Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't nee

  • Python中的Classes和Metaclasses详解

    类和对象 类和函数一样都是Python中的对象.当一个类定义完成之后,Python将创建一个"类对象"并将其赋值给一个同名变量.类是type类型的对象(是不是有点拗口?). 类对象是可调用的(callable,实现了 __call__方法),并且调用它能够创建类的对象.你可以将类当做其他对象那么处理.例如,你能够给它们的属性赋值,你能够将它们赋值给一个变量,你可以在任何可调用对象能够用的地方使用它们,比如在一个map中.事实上当你在使用map(str, [1,2,3])的时候,是将一个

  • 深入理解Python中的元类(metaclass)

    译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及在什么情况下需要进行元编程.于是e-satis同学给出了神一般的回复,该回复获得了985点的赞同点数,更有人评论说这段回复应该加入到Python的官方文档中去.而e-satis同学本人在Stack Overflow中的声望积分也高达6

  • Python使用metaclass实现Singleton模式的方法

    本文实例讲述了Python使用metaclass实现Singleton模式的方法.分享给大家供大家参考.具体实现方法如下: class Singleton(type): def __call__(cls, *args, **kwargs): print "Singleton call" if not hasattr(cls, 'instance'): cls.instance = super(Singleton, cls).__call__(*args, **kwargs) retur

  • 举例讲解Python中metaclass元类的创建与使用

    元类是可以让你定义某些类是如何被创建的.从根本上说,赋予你如何创建类的控制权. 元类也是一个类,是一个type类.   元类一般用于创建类.在执行类定义时,解释器必须要知道这个类的正确的元类,如果此属性没有定义,它会向上查找父类中的__metaclass__属性.如果还没发现,就查找全局变量.   对于传统类来说,它们的元类是types.ClassType.   元类也有构造器,传递三个参数:类名,从基类继承数据的元组,和类属性字典. 下面我们来定义一个元类,要求写类的时候必须给类提供一个__s

  • 详解python单例模式与metaclass

    单例模式的实现方式 将类实例绑定到类变量上 class Singleton(object): _instance = None def __new__(cls, *args): if not isinstance(cls._instance, cls): cls._instance = super(Singleton, cls).__new__(cls, *args) return cls._instance 但是子类在继承后可以重写__new__以失去单例特性 class D(Singleto

  • 详解python metaclass(元类)

    元编程,一个听起来特别酷的词,强大的Lisp在这方面是好手,对于Python,尽管没有完善的元编程范式,一些天才的开发者还是创作了很多元编程的魔法.Django的ORM就是元编程的一个很好的例子. 本篇的概念和例子皆在Python3.6环境下 一切都是对象 Python里一切都是对象(object),基本数据类型,如数字,字串,函数都是对象.对象可以由类(class)进行创建.既然一切都是对象,那么类是对象吗? 是的,类也是对象,那么又是谁创造了类呢?答案也很简单,也是类,一个能创作类的类,就像

  • 一文详解Python中实现单例模式的几种常见方式

    目录 Python 中实现单例模式的几种常见方式 元类(Metaclass): 装饰器(Decorator): 模块(Module): new 方法: Python 中实现单例模式的几种常见方式 元类(Metaclass): class SingletonType(type): """ 单例元类.用于将普通类转换为单例类. """ _instances = {} # 存储单例实例的字典 def __call__(cls, *args, **kwa

  • 详解Python中__new__方法的作用

    目录 前言 一.__new__方法简介 1.初始化数据加载+解析类实例 2.初始化数据加载重写new方法+解析类实例 二.单例模式 1.用new方法如何实现单例模式 2.如何控制类仅执行一次初始化方法 三.多例模式 总结 前言 Python中类的构造方法__new__方法有何作用? Python类中有些方法名.属性名的前后都添加__双下画线,这种方法.属性通常属于Python的特殊方法和特殊属性.通过重写这些方法或直接调用这些方法来实现特殊功能.今天来聊聊构造方法__new__实际程序的应用场景

  • 一文详解Python中PO模式的设计与实现

    目录 什么是PO模式 PO 三层模式 PO 设计模式的优点 将改写的脚本转为PO设计模式 构建基础的 BasePage 层 构建首页的 Page 层(HomePage) 构建登录页的 Page 层(LoginPage) 构建 首页 - 订单 - 支付 流程的 Page 层(OrderPage) PO 设计模式下测试Case的改造 在使用 Python 进行编码的时候,会使用自身自带的编码设计格式,比如说最常见的单例模式,稍微抽象一些的抽象工厂模式等等… 在利用 Python 做自动化测试的时候,

  • 详解python里使用正则表达式的分组命名方式

    详解python里使用正则表达式的分组命名方式 分组匹配的模式,可以通过groups()来全部访问匹配的元组,也可以通过group()函数来按分组方式来访问,但是这里只能通过数字索引来访问,如果某一天产品经理需要修改需求,让你在它们之中添加一个分组,这样一来,就会导致匹配的数组的索引的变化,作为开发人员的你,必须得一行一行代码地修改.因此聪明的开发人员又想到一个好方法,把这些分组进行命名,只需要对名称进行访问分组,不通过索引来访问了,就可以避免这个问题.那么怎么样来命名呢?可以采用(?P<nam

  • 详解Python实现多进程异步事件驱动引擎

    本文介绍了详解Python实现多进程异步事件驱动引擎,分享给大家,具体如下: 多进程异步事件驱动逻辑 逻辑 code # -*- coding: utf-8 -*- ''' author: Jimmy contact: 234390130@qq.com file: eventEngine.py time: 2017/8/25 上午10:06 description: 多进程异步事件驱动引擎 ''' __author__ = 'Jimmy' from multiprocessing import

  • 详解Python import方法引入模块的实例

    详解Python import方法引入模块的实例 在Python用import或者from-import或者from-import-as-来导入相应的模块,作用和使用方法与C语言的include头文件类似.其实就是引入某些成熟的函数库和成熟的方法,避免重复造轮子,提高开发速度. python的import方法可以引入系统的模块,也可以引入我们自己写好的共用模块,这点和PHP非常相似,但是它们的具体细节还不是很一样.因为php是在引入的时候指明引入文件的具体路径,而python中不能够写文件路径进

  • 详解python中executemany和序列的使用方法

    详解python中executemany和序列的使用方法 一 代码 import sqlite3 persons=[ ("Jim","Green"), ("Hu","jie") ] conn=sqlite3.connect(":memory:") conn.execute("CREATE TABLE person(firstname,lastname)") conn.executeman

  • 详解Python 序列化Serialize 和 反序列化Deserialize

    详解Python 序列化Serialize 和 反序列化Deserialize 序列化 (serialization) 序列化是将对象状态转换为可保持或传输的格式的过程.与序列化相对的是反序列化, 它将流转换为对象.这两个过程结合起来,可以轻松地存储和传输数据. 序列化和反序列化的目的 1.以某种存储形式使自定义对象持久化: 2.将对象从一个地方传递到另一个地方. 3.使程序更具维护性 序列化   由于存在于内存中的对象都是暂时的,无法长期驻存,为了把对象的状态保持下来,这时需要把对象写入到磁盘

随机推荐