资讯专栏INFORMATION COLUMN

python单例模式与metaclass

G9YH / 3362人阅读

摘要:看一下中这两者以及的实现前面提到类相当于元类的实例化,再联系创建单例模式时使用的函数,用的是,其实用三种中任何一种都是可以的,来看一下使用元类时各方法的调用情况结果元类的和只在创建类调用了一次,而创建的实例时,每次都会调用元类的方法

单例模式的实现方式

将类实例绑定到类变量上

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: "Foo" () {"__module__": "__main__", "__metaclass__": , "__init__": init at 0x106fd5320>}
init: "Foo" () {"__module__": "__main__", "__metaclass__": , "__init__": init at 0x106fd5320>}
call: ("a",)
init: <__main__.Foo object at 0x106fee990> ("a",) {}
call: ("b",)
init: <__main__.Foo object at 0x106feea50> ("b",) {}

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/45418.html

相关文章

  • Python单例模式(Singleton)的N种实现

    摘要:本篇文章总结了目前主流的实现单例模式的方法供读者参考。使用实现单例模式同样,我们在类的创建时进行干预,从而达到实现单例的目的。 很多初学者喜欢用 全局变量 ,因为这比函数的参数传来传去更容易让人理解。确实在很多场景下用全局变量很方便。不过如果代码规模增大,并且有多个文件的时候,全局变量就会变得比较混乱。你可能不知道在哪个文件中定义了相同类型甚至重名的全局变量,也不知道这个变量在程序的某...

    Maxiye 评论0 收藏0
  • Python 中的单例模式

    摘要:在中,我们可以用多种方法来实现单例模式使用模块使用使用装饰器使用元类使用模块其实,的模块就是天然的单例模式,因为模块在第一次导入时,会生成文件,当第二次导入时,就会直接加载文件,而不会再次执行模块代码。 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对...

    khlbat 评论0 收藏0
  • Python中的单例模式

    摘要:使用元类可以控制类的创建过程,它主要做三件事拦截类的创建修改类的定义返回修改后的类使用元类实现单例模式的代码如下执行结果 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。 比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 ...

    church 评论0 收藏0
  • python设计模式-单例模式

    摘要:实现实现单例模式有多种方案使用提供了非常易用的类,只要继承它,就会成为单例。参考链接单例模式最后,感谢女朋友支持。 问题:现代化的巧克力工厂具备计算机控制的巧克力锅炉。锅炉做的事情就是把巧克力和牛奶融在一起,然后送到下一个阶段,以制成巧克力棒。下边是一个巧克力公司锅炉控制器的代码,仔细观察一下,这段代码有什么问题? class ChocolateBoiler(object): ...

    darkbug 评论0 收藏0
  • Python下的设计模式总结----创建型设计模式(一)

    摘要:最近在学习设计模式而开发的语言中比较中意的就是了在这里总结下设计模式一般分为三大类构造型结构型行为型先从创建型设计模式开始创建型设计模式包括单例模式抽象工厂模式工厂方法模式生成器模式惰性初始化模式对象池模式原型模式单例模式单例模式的定义是保 最近在学习设计模式,而开发的语言中比较中意的就是python了,在这里总结下. 设计模式一般分为三大类:构造型,结构型,行为型 先从创建型设计模式...

    lewif 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<