欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

python單例模式的多種實(shí)現(xiàn)方法

 更新時(shí)間:2019年07月26日 09:52:04   作者:谷子的  
這篇文章主要介紹了python單例模式的多種實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

前言

單例模式(Singleton Pattern),是一種軟件設(shè)計(jì)模式,是類只能實(shí)例化一個(gè)對(duì)象,

目的是便于外界的訪問(wèn),節(jié)約系統(tǒng)資源,如果希望系統(tǒng)中 只有一個(gè)對(duì)象可以訪問(wèn),就用單例模式,

顯然單例模式的要點(diǎn)有三個(gè);一是某個(gè)類只能有一個(gè)實(shí)例;二是它必須自行創(chuàng)建這個(gè)實(shí)例;三是它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。

在 Python 中,我們可以用多種方法來(lái)實(shí)現(xiàn)單例模式:

  • 使用模塊
  • 使用 __new__
  • 使用裝飾器(decorator)
  • 使用元類(metaclass)

概念

簡(jiǎn)單說(shuō),單例模式(也叫單件模式)的作用就是保證在整個(gè)應(yīng)用程序的生命周期中,任何一個(gè)時(shí)刻,單例類的實(shí)例都只存在一個(gè)(當(dāng)然也可以不存在)

例子:

一臺(tái)計(jì)算機(jī)上可以連好幾個(gè)打印機(jī),但是這個(gè)計(jì)算機(jī)上的打印程序只能有一個(gè),這里就可以通過(guò)單例模式來(lái)避免兩個(gè)打印作業(yè)同時(shí)輸出到打印機(jī)中,即在整個(gè)的打印過(guò)程中我只有一個(gè)打印程序的實(shí)例。

super(B, self).__init__()是這樣理解的:super(B, self)首先找到B的父類(就是類A),然后把類B的對(duì)象self轉(zhuǎn)換為類A的對(duì)象(通過(guò)某種方式,一直沒有考究是什么方式,慚愧),然后“被轉(zhuǎn)換”的類A對(duì)象調(diào)用自己的__init__函數(shù)??紤]到super中只有指明子類的機(jī)制,因此,在多繼承的類定義中,通常我們保留使用類似代碼段1的方法。

1. super并不是一個(gè)函數(shù),是一個(gè)類名,形如super(B, self)事實(shí)上調(diào)用了super類的初始化函數(shù),
產(chǎn)生了一個(gè)super對(duì)象;

2. super類的初始化函數(shù)并沒有做什么特殊的操作,只是簡(jiǎn)單記錄了類類型和具體實(shí)例;

3. super(B, self).func的調(diào)用并不是用于調(diào)用當(dāng)前類的父類的func函數(shù);

4. Python的多繼承類是通過(guò)mro的方式來(lái)保證各個(gè)父類的函數(shù)被逐一調(diào)用,而且保證每個(gè)父類函數(shù)
只調(diào)用一次(如果每個(gè)類都使用super);

5. 混用super類和非綁定的函數(shù)是一個(gè)危險(xiǎn)行為,這可能導(dǎo)致應(yīng)該調(diào)用的父類函數(shù)沒有調(diào)用或者一
個(gè)父類函數(shù)被調(diào)用多次。

__new__: 對(duì)象的創(chuàng)建,是一個(gè)靜態(tài)方法,第一個(gè)參數(shù)是cls。(想想也是,不可能是self,對(duì)象還沒創(chuàng)建,哪來(lái)的self)

__init__ : 對(duì)象的初始化, 是一個(gè)實(shí)例方法,第一個(gè)參數(shù)是self。

__new__方法在類定義中不是必須寫的,如果沒定義,默認(rèn)會(huì)調(diào)用object.__new__去創(chuàng)建一個(gè)對(duì)象。如果定義了,就是override,可以custom創(chuàng)建對(duì)象的行為。

聰明的讀者可能想到,既然__new__可以custom對(duì)象的創(chuàng)建,那我在這里做一下手腳,每次創(chuàng)建對(duì)象都返回同一個(gè),那不就是單例模式了嗎?沒錯(cuò),就是這樣??梢杂^摩《飄逸的python - 單例模式亂彈》

定義單例模式時(shí),因?yàn)樽远x的__new__重載了父類的__new__,所以要自己顯式調(diào)用父類的__new__,即object.__new__(cls, *args, **kwargs),或者用super()。,不然就不是extend原來(lái)的實(shí)例了,而是替換原來(lái)的實(shí)例。

代碼

import threading
class Signleton(object):
  def __init__(self):
    print("__init__ method called")
  def __new__(cls):
    print("__new__ method called")
    mutex=threading.Lock()
    mutex.acquire() # 上鎖,防止多線程下出問(wèn)題
    if not hasattr(cls, 'instance'):
      cls.instance = super(LogSignleton, cls).__new__(cls)
    mutex.release()
    return cls.instance 
if __name__ == '__main__':
obj = Signleton()

輸出結(jié)果:

>>> ================================ RESTART ================================
>>>
__new__ method called
__init__ method called
>>> 

說(shuō)明

1.從輸出結(jié)果來(lái)看,最先調(diào)用 __new__ 方法,然后調(diào)用__init__方法

2. __new__ 通常用于控制生成一個(gè)新實(shí)例的過(guò)程,它是類級(jí)別的方法。

3. __init__ 通常用于初始化一個(gè)新實(shí)例,控制這個(gè)初始化的過(guò)程,比如添加一些屬性,做一些額外的操作,發(fā)生在類實(shí)例被創(chuàng)建完以后。它是實(shí)例級(jí)別的方法。

方法1

__new__ 在__init__初始化前,就已經(jīng)實(shí)例化對(duì)象,可以利用這個(gè)方法實(shí)現(xiàn)單例模式。

print '----------------------方法1--------------------------' 
#方法1,實(shí)現(xiàn)__new__方法 
#并在將一個(gè)類的實(shí)例綁定到類變量_instance上, 
#如果cls._instance為None說(shuō)明該類還沒有實(shí)例化過(guò),實(shí)例化該類,并返回 
#如果cls._instance不為None,直接返回cls._instance 
class Singleton(object): 
  def __new__(cls, *args, **kw): 
    if not hasattr(cls, '_instance'): 
      orig = super(Singleton, cls) 
      cls._instance = orig.__new__(cls, *args, **kw) 
    return cls._instance 
 
class MyClass(Singleton): 
  a = 1 
 
one = MyClass() 
two = MyClass() 
 
two.a = 3 
print one.a 
#3 
#one和two完全相同,可以用id(), ==, is檢測(cè) 
print id(one) 
#29097904 
print id(two) 
#29097904 
print one == two 
#True 
print one is two 
#True

方法2

print '----------------------方法2--------------------------' 
#方法2,共享屬性;所謂單例就是所有引用(實(shí)例、對(duì)象)擁有相同的狀態(tài)(屬性)和行為(方法) 
#同一個(gè)類的所有實(shí)例天然擁有相同的行為(方法), 
#只需要保證同一個(gè)類的所有實(shí)例具有相同的狀態(tài)(屬性)即可 
#所有實(shí)例共享屬性的最簡(jiǎn)單最直接的方法就是__dict__屬性指向(引用)同一個(gè)字典(dict) 
#可參看:http://code.activestate.com/recipes/66531/ 
class Borg(object): 
  _state = {} 
  def __new__(cls, *args, **kw): 
    ob = super(Borg, cls).__new__(cls, *args, **kw) 
    ob.__dict__ = cls._state 
    return ob 
 
class MyClass2(Borg): 
  a = 1 
 
one = MyClass2() 
two = MyClass2() 
 
#one和two是兩個(gè)不同的對(duì)象,id, ==, is對(duì)比結(jié)果可看出 
two.a = 3 
print one.a 
#3 
print id(one) 
#28873680 
print id(two) 
#28873712 
print one == two 
#False 
print one is two 
#False 
#但是one和two具有相同的(同一個(gè)__dict__屬性),見: 
print id(one.__dict__) 
#30104000 
print id(two.__dict__) 
#30104000 

方法3

print '----------------------方法3--------------------------' 
#方法3:本質(zhì)上是方法1的升級(jí)(或者說(shuō)高級(jí))版 
#使用__metaclass__(元類)的高級(jí)python用法 
class Singleton2(type): 
  def __init__(cls, name, bases, dict): 
    super(Singleton2, cls).__init__(name, bases, dict) 
    cls._instance = None 
  def __call__(cls, *args, **kw): 
    if cls._instance is None: 
      cls._instance = super(Singleton2, cls).__call__(*args, **kw) 
    return cls._instance 
 
class MyClass3(object): 
  __metaclass__ = Singleton2 
 
one = MyClass3() 
two = MyClass3() 
 
two.a = 3 
print one.a 
#3 
print id(one) 
#31495472 
print id(two) 
#31495472 
print one == two 
#True 
print one is two 
#True 

方法4

print '----------------------方法4--------------------------' 
#方法4:也是方法1的升級(jí)(高級(jí))版本, 
#使用裝飾器(decorator), 
#這是一種更pythonic,更elegant的方法, 
#單例類本身根本不知道自己是單例的,因?yàn)樗旧?自己的代碼)并不是單例的 
def singleton(cls, *args, **kw): 
  instances = {} 
  def _singleton(): 
    if cls not in instances: 
      instances[cls] = cls(*args, **kw) 
    return instances[cls] 
  return _singleton 
 
@singleton 
class MyClass4(object): 
  a = 1 
  def __init__(self, x=0): 
    self.x = x 
 
one = MyClass4() 
two = MyClass4() 
 
two.a = 3 
print one.a 
#3 
print id(one) 
#29660784 
print id(two) 
#29660784 
print one == two 
#True 
print one is two 
#True 
one.x = 1 
print one.x 
#1 
print two.x 

單例模式

單例模式(Singleton Pattern)是一種常用的軟件設(shè)計(jì)模式,該模式的主要目的是確保某一個(gè)類只有一個(gè)實(shí)例存在。當(dāng)你希望在整個(gè)系統(tǒng)中,某個(gè)類只能出現(xiàn)一個(gè)實(shí)例時(shí),單例對(duì)象就能派上用場(chǎng)。

比如,某個(gè)服務(wù)器程序的配置信息存放在一個(gè)文件中,客戶端通過(guò)一個(gè) AppConfig 的類來(lái)讀取配置文件的信息。如果在程序運(yùn)行期間,有很多地方都需要使用配置文件的內(nèi)容,也就是說(shuō),很多地方都需要?jiǎng)?chuàng)建 AppConfig 對(duì)象的實(shí)例,這就導(dǎo)致系統(tǒng)中存在多個(gè) AppConfig 的實(shí)例對(duì)象,而這樣會(huì)嚴(yán)重浪費(fèi)內(nèi)存資源,尤其是在配置文件內(nèi)容很多的情況下。事實(shí)上,類似 AppConfig 這樣的類,我們希望在程序運(yùn)行期間只存在一個(gè)實(shí)例對(duì)象。

在 Python 中,我們可以用多種方法來(lái)實(shí)現(xiàn)單例模式:

  • 使用模塊
  • 使用 __new__
  • 使用裝飾器(decorator)
  • 使用元類(metaclass)

使用模塊

其實(shí),Python 的模塊就是天然的單例模式,因?yàn)槟K在第一次導(dǎo)入時(shí),會(huì)生成 .pyc 文件,當(dāng)?shù)诙螌?dǎo)入時(shí),就會(huì)直接加載 .pyc 文件,而不會(huì)再次執(zhí)行模塊代碼。因此,我們只需把相關(guān)的函數(shù)和數(shù)據(jù)定義在一個(gè)模塊中,就可以獲得一個(gè)單例對(duì)象了。如果我們真的想要一個(gè)單例類,可以考慮這樣做:

# mysingleton.py
class My_Singleton(object):
  def foo(self):
    pass
 
my_singleton = My_Singleton()

將上面的代碼保存在文件 mysingleton.py 中,然后這樣使用:

from mysingleton import my_singleton
my_singleton.foo()

使用 __new__
為了使類只能出現(xiàn)一個(gè)實(shí)例,我們可以使用 __new__ 來(lái)控制實(shí)例的創(chuàng)建過(guò)程,代碼如下:

class Singleton(object):
  _instance = None
  def __new__(cls, *args, **kw):
    if not cls._instance:
      cls._instance = super(Singleton, cls).__new__(cls, *args, **kw) 
    return cls._instance 
 
class MyClass(Singleton): 
  a = 1

在上面的代碼中,我們將類的實(shí)例和一個(gè)類變量 _instance 關(guān)聯(lián)起來(lái),如果 cls._instance 為 None 則創(chuàng)建實(shí)例,否則直接返回 cls._instance。

執(zhí)行情況如下:

>>> one = MyClass()
>>> two = MyClass()
>>> one == two
True
>>> one is two
True
>>> id(one), id(two)
(4303862608, 4303862608)

使用裝飾器

我們知道,裝飾器(decorator)可以動(dòng)態(tài)地修改一個(gè)類或函數(shù)的功能。這里,我們也可以使用裝飾器來(lái)裝飾某個(gè)類,使其只能生成一個(gè)實(shí)例,代碼如下:

from functools import wraps
 
def singleton(cls):
  instances = {}
  @wraps(cls)
  def getinstance(*args, **kw):
    if cls not in instances:
      instances[cls] = cls(*args, **kw)
    return instances[cls]
  return getinstance
 
@singleton
class MyClass(object):
  a = 1

在上面,我們定義了一個(gè)裝飾器 singleton,它返回了一個(gè)內(nèi)部函數(shù) getinstance,該函數(shù)會(huì)判斷某個(gè)類是否在字典 instances 中,如果不存在,則會(huì)將 cls 作為 key,cls(*args, **kw) 作為 value 存到 instances 中,否則,直接返回 instances[cls]。

使用 metaclass

元類(metaclass)可以控制類的創(chuàng)建過(guò)程,它主要做三件事:

  • 攔截類的創(chuàng)建
  • 修改類的定義
  • 返回修改后的類

使用元類實(shí)現(xiàn)單例模式的代碼如下:

class Singleton(type):
  _instances = {}
  def __call__(cls, *args, **kwargs):
    if cls not in cls._instances:
      cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
    return cls._instances[cls]
 
# Python2
class MyClass(object):
  __metaclass__ = Singleton
 
# Python3
# class MyClass(metaclass=Singleton):
#  pass

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Python中的探索性數(shù)據(jù)分析(功能式)

    Python中的探索性數(shù)據(jù)分析(功能式)

    這篇文章主要介紹了功能式Python中的探索性數(shù)據(jù)分析的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-12-12
  • Python 微信公眾號(hào)文章爬取的示例代碼

    Python 微信公眾號(hào)文章爬取的示例代碼

    這篇文章主要介紹了Python 微信公眾號(hào)文章爬取的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Python3+Appium安裝使用教程

    Python3+Appium安裝使用教程

    這篇文章主要介紹了Python3+Appium安裝使用教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • python opencv 檢測(cè)移動(dòng)物體并截圖保存實(shí)例

    python opencv 檢測(cè)移動(dòng)物體并截圖保存實(shí)例

    這篇文章主要介紹了python opencv 檢測(cè)移動(dòng)物體并截圖保存實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-03-03
  • 淺談Python traceback的優(yōu)雅處理

    淺談Python traceback的優(yōu)雅處理

    這篇文章主要介紹了淺談Python traceback的優(yōu)雅處理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • Python 裝飾器使用詳解

    Python 裝飾器使用詳解

    裝飾器是Python語(yǔ)言中的高級(jí)語(yǔ)法。主要的功能是對(duì)一個(gè)函數(shù)、方法、或者類進(jìn)行加工,作用是為已經(jīng)存在的對(duì)象添加額外的功能,提升代碼的可讀性。裝飾器是設(shè)計(jì)模式的一種,被用于有切面需求的場(chǎng)景,較為經(jīng)典的有插入日志、性能測(cè)試、事務(wù)處理等
    2017-07-07
  • Python decimal模塊的使用示例詳解

    Python decimal模塊的使用示例詳解

    decimal 模塊decimal意思為十進(jìn)制,這個(gè)模塊提供了十進(jìn)制浮點(diǎn)運(yùn)算支持,本篇文章主要給大家講解Python decimal模塊的使用,需要的朋友可以參考下
    2023-03-03
  • Python的pycurl包用法簡(jiǎn)介

    Python的pycurl包用法簡(jiǎn)介

    這篇文章主要介紹了Python的pycurl包用法簡(jiǎn)介,文中羅列了其下模塊中的一些常用方法,需要的朋友可以參考下
    2015-11-11
  • Python argparse中的action=store_true用法小結(jié)

    Python argparse中的action=store_true用法小結(jié)

    這篇文章主要介紹了Python argparse中的action=store_true用法小結(jié),本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-02-02
  • Python實(shí)現(xiàn)自動(dòng)識(shí)別并填加驗(yàn)證碼的示例代碼

    Python實(shí)現(xiàn)自動(dòng)識(shí)別并填加驗(yàn)證碼的示例代碼

    實(shí)現(xiàn)自動(dòng)識(shí)別網(wǎng)頁(yè)中的驗(yàn)證碼并填寫,需要結(jié)合使用網(wǎng)絡(luò)爬蟲技術(shù)、圖像識(shí)別(OCR),以及可能的瀏覽器自動(dòng)化工具(如Selenium),本文給大家介紹了Python實(shí)現(xiàn)自動(dòng)識(shí)別并填加驗(yàn)證碼的示例,需要的朋友可以參考下
    2024-06-06

最新評(píng)論