首頁  >  文章  >  後端開發  >  Python元類別下單例模式的使用介紹(程式碼範例)

Python元類別下單例模式的使用介紹(程式碼範例)

不言
不言原創
2018-09-12 15:13:211690瀏覽

本篇文章帶給大家的內容是關於Python元類下單例模式的使用介紹(程式碼範例) ,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

#1、什麼是Python元類別

#參考文章什麼是Python元類別? Python元類別的介紹

2、什麼是單例模式

單例模式(Singleton pattern)是常用的軟體設計模式。在它的核心結構中只包含一個被稱為單例的特殊類別。透過單例模式可以確保系統中一個類別只有一個實例而且該實例易於外界訪問,從而方便對實例個數的控制並節約系統資源。如果希望在系統中某個類別的物件只能存在一個,單例模式是最好的解決方案。

如何保證一個類別只有一個實例並且這個實例很容易被存取呢?定義一個全域變數可以確保物件隨時都可以被訪問,但不能防止我們實例化多個物件。一個更好的解決辦法是讓類別本身負責保存它的唯一實例。這個類別可以保證沒有其他實例被創建,並且它可以提供一個訪問該實例的方法。這就是單例模式的模式動機。

3、利用__new__實作單例

# -*- coding: utf8 -*-

class Singleton(object):
    def __init__(self):
        print 'entrance of __init__'

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

if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()

    print s1, s2

 Python中通常利用__new__函數實作單例模式。 __new__函數負責建構對象,類似C 中的建構子。因此為了讓類別只能建立一個實例對象,我們可以重載__new__函數的行為,使其只能建構一個實例。在上述程式碼中,賦予Singleton類別了一個_instance屬性,如果_instance屬性為None則建立實例對象,並使_instance屬性參考(指向)該對象,否則直接傳回_instance所引用的物件。因此程式碼中的s1和s2實際上引用了同一個記憶體物件。

4、利用元類別__call__實作單例

# -*- coding: utf8 -*-

# 单例模式
class SingletonMetaClass(type):
    def __init__(cls, *args, **kwargs):
        """
        初始化类
        :param args:
        :param kwargs:
        """
        print 'MetaClass.__init__ called'
        print cls._instance
        super(SingletonMetaClass, cls).__init__(*args, **kwargs)


    def __new__(cls, name, bases, attrs):
        """
        创建类,负责类的行为和属性的创建
        :param name:
        :param bases:
        :param attrs:
        :return:
        """
        print 'MetaClass.__new__ called'

        # 单例模式
        cls._instance = None

        return type.__new__(cls, name, bases, attrs)

    # __call__方法其实和类的创建过程和实例化没有多大关系了,定义了__call__方法才能被使用函数的方式执行。
    # 被该元类创建的类,属于该元类的一个实例。因此创建其实例的时候,会调用元类的__call_方法
    def __call__(cls, *args, **kwargs):
        """
        使类变为可调用对象
        :param args:
        :param kwargs:
        :return:
        """
        print 'MetaClass.__call__ called'
        if cls._instance is None:
            # 这里会去调用类的__new__函数
            cls._instance = super.__call__(SingletonMetaClass, cls).__call__(*args, **kwargs)
        return cls._instance

class A():
    __metaclass__ = SingletonMetaClass

    def __new__(cls, *args, **kwargs):
        print 'A.__new__ called'
        return super(A, cls).__new__(cls, *args, **kwargs)

if __name__ == '__main__':
    # 因为类A是SingletonMetaClass的一个实例,执行A()时会调用元类SingletonMetaClass的__call__方法
    a1 = A()
    print a1
    a2 = A()
    print a2

 我們知道,在Python中類別也是對象,元類別是建立類別的類,因此類別其實是元類別的實例物件。在Python中,如果一個物件定義了__call__方法,那麼該物件為可呼叫對象,意思是可以用呼叫函數的形式來呼叫物件。

Python的__new__方法負責建立對象,__init__方法負責初始化物件。在上述程式碼中,只有在創建類別A後才能建立類別A的物件,因此為了先建立出類別A,SingletonMetaClass的__new__和__init__方法會先被執行。當執行語句A()建立類別A的物件時,根據__call__方法的定義,由於類別A是元類別SingletonMetaClass的對象,所以可以預料元類別SingletonMetaClass的__call__方法會呼叫。

因此上述程式碼中SiingletonMetaClass的__new__和__init__方法只執行一次,而每次呼叫A()建立類別A的實例時,都會呼叫SingletonMetaClass的__call__方法。因此為了實現單例模式,我們在元類別的__call__方法中判斷了cls的_instance屬性是否為None,如果為None則呼叫元類父類(即type)的__call__方法,type.__call_ _方法會呼叫類別A的__new__方法建立類別A的一個實例,然後將_instance屬性指向該實例,從而實現只有一個實例。以下是一次執行結果:

MetaClass.__new__ called
MetaClass.__init__ called
None
MetaClass.__call__ called
A.__new__ called
<__main__.A object at 0x00000000036D2EB8>
MetaClass.__call__ called
<__main__.A object at 0x00000000036D2EB8>

相關推薦:

Python使用設計模式中的責任鏈模式與迭代器模式的範例

Python使用redis pool的單例實作方式介紹

#

以上是Python元類別下單例模式的使用介紹(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn