Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Lima cara untuk menulis mod tunggal dalam Python

Lima cara untuk menulis mod tunggal dalam Python

WBOY
WBOYke hadapan
2023-05-26 22:31:241519semak imbas

Python 实现单例模式的五种写法

Singleton Pattern ialah corak reka bentuk perisian yang biasa digunakan Tujuan utama corak ini adalah untuk memastikan bahawa hanya satu contoh kelas tertentu wujud. Objek singleton berguna apabila anda mahu hanya satu contoh kelas tertentu muncul dalam keseluruhan sistem.

Sebagai contoh, maklumat konfigurasi program pelayan disimpan dalam fail dan pelanggan membaca maklumat fail konfigurasi melalui kelas AppConfig. Jika semasa menjalankan program, kandungan fail konfigurasi perlu digunakan di banyak tempat, iaitu, contoh objek AppConfig perlu dibuat di banyak tempat, ini akan membawa kepada kewujudan berbilang contoh AppConfig objek dalam sistem, yang akan membazirkan sumber memori, terutamanya jika fail konfigurasi mengandungi banyak kandungan.

Malah, untuk kelas seperti AppConfig, kami berharap hanya satu objek contoh akan wujud semasa program dijalankan.

Dalam Python, kita boleh menggunakan pelbagai kaedah untuk melaksanakan corak tunggal:

  1. Menggunakan modul
  2. Menggunakan penghias
  3. Gunakan kelas
  4. Berdasarkan kaedah __new__
  5. Laksanakan berdasarkan kaedah metaclass

Perincian berikut pengenalan:

Menggunakan modul

Malah, modul Python adalah mod tunggal semula jadi, kerana apabila modul diimport buat kali pertama, fail .pyc akan dihasilkan . Apabila diimport untuk kali kedua, fail .pyc akan dimuatkan terus tanpa melaksanakan kod modul sekali lagi.

Oleh itu, kita hanya perlu mentakrifkan fungsi dan data yang berkaitan dalam modul untuk mendapatkan objek tunggal.

Jika kami benar-benar mahukan kelas tunggal, kami boleh mempertimbangkan untuk melakukan ini:

class Singleton(object):
 def foo(self):
 pass
singleton = Singleton()

Simpan kod di atas dalam fail mysingleton.py Apabila anda ingin menggunakannya, terus masuk Import objek dalam fail ini daripada fail lain. Objek ini ialah objek mod tunggal

from mysingleton import singleton

Gunakan penghias

def Singleton(cls):
 _instance = {}
 def _singleton(*args, **kargs):
 if cls not in _instance:
 _instance[cls] = cls(*args, **kargs)
 return _instance[cls]
 return _singleton
@Singleton
class A(object):
 a = 1
 def __init__(self, x=0):
 self.x = x
a1 = A(2)
a2 = A(3)

Gunakan kelas

class Singleton(object):
 def __init__(self):
 pass
 @classmethod
 def instance(cls, *args, **kwargs):
 if not hasattr(Singleton, "_instance"):
 Singleton._instance = Singleton(*args, **kwargs)
 return Singleton._instance

Secara amnya, semua orang berpendapat bahawa ini melengkapkan mod tunggal, tetapi akan ada masalah apabila menggunakan multi-threading:

class Singleton(object):
 def __init__(self):
 pass
 @classmethod
 def instance(cls, *args, **kwargs):
 if not hasattr(Singleton, "_instance"):
 Singleton._instance = Singleton(*args, **kwargs)
 return Singleton._instance
import threading
def task(arg):
 obj = Singleton.instance()
 print(obj)
for i in range(10):
 t = threading.Thread(target=task,args=[i,])
 t.start()

Selepas program dilaksanakan, hasil cetakan adalah seperti berikut:

<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>
<__main__.Singleton object at 0x02C933D0>

Lihat Tiada masalah, tetapi ia adalah kerana kelajuan pelaksanaan terlalu cepat Jika terdapat beberapa operasi IO dalam kaedah __init__, anda akan mendapati masalahnya.

Di bawah kami mensimulasikan melalui time.sleep Kami menambah kod berikut pada kaedah __init__ di atas:

def __init__(self):
 import time
 time.sleep(1)

Selepas melaksanakan semula program, hasilnya adalah seperti berikut:

<__main__.Singleton object at 0x034A3410>
<__main__.Singleton object at 0x034BB990>
<__main__.Singleton object at 0x034BB910>
<__main__.Singleton object at 0x034ADED0>
<__main__.Singleton object at 0x034E6BD0>
<__main__.Singleton object at 0x034E6C10>
<__main__.Singleton object at 0x034E6B90>
<__main__.Singleton object at 0x034BBA30>
<__main__.Singleton object at 0x034F6B90>
<__main__.Singleton object at 0x034E6A90>

Timbul masalah! Singleton yang dibuat dengan cara di atas tidak boleh menyokong multi-threading.


Penyelesaian: Kuncinya! Bahagian yang tidak berkunci dilaksanakan secara serentak, dan bahagian yang dikunci dilaksanakan secara bersiri, yang mengurangkan kelajuan tetapi memastikan keselamatan data.

import time
import threading
class Singleton(object):
 _instance_lock = threading.Lock()
 def __init__(self):
 time.sleep(1)
 @classmethod
 def instance(cls, *args, **kwargs):
 with Singleton._instance_lock:
 if not hasattr(Singleton, "_instance"):
 Singleton._instance = Singleton(*args, **kwargs)
 return Singleton._instance
def task(arg):
 obj = Singleton.instance()
 print(obj)
for i in range(10):
 t = threading.Thread(target=task,args=[i,])
 t.start()
time.sleep(20)
obj = Singleton.instance()
print(obj)

Hasil cetakan adalah seperti berikut:

<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>
<__main__.Singleton object at 0x02D6B110>

Ini hampir sama, tetapi masih terdapat masalah kecil, iaitu, apabila program dijalankan, selepas masa.sleep(20 ) dilaksanakan, objek diwujudkan di bawah , ia sudah berada dalam mod tunggal.


Tetapi kami masih menambah kunci, yang tidak bagus. Mari lakukan pengoptimuman dan tukar kaedah instance kepada yang berikut:

@classmethod
def instance(cls, *args, **kwargs):
 if not hasattr(Singleton, "_instance"):
 with Singleton._instance_lock:
 if not hasattr(Singleton, "_instance"):
 Singleton._instance = Singleton(*args, **kwargs)
 return Singleton._instance

Dengan cara ini, seseorang boleh menyokong berbilang rangkaian. Mod tunggal telah selesai. +

import time
import threading
class Singleton(object):
 _instance_lock = threading.Lock()
 def __init__(self):
 time.sleep(1)
 @classmethod
 def instance(cls, *args, **kwargs):
 if not hasattr(Singleton, "_instance"):
 with Singleton._instance_lock:
 if not hasattr(Singleton, "_instance"):
 Singleton._instance = Singleton(*args, **kwargs)
 return Singleton._instance
def task(arg):
 obj = Singleton.instance()
 print(obj)
for i in range(10):
 t = threading.Thread(target=task,args=[i,])
 t.start()
time.sleep(20)
obj = Singleton.instance()
print(obj)

Mod tunggal yang dilaksanakan dengan cara ini mempunyai sekatan penggunaan kemudiannya mesti dilakukan melalui obj = Singleton.instance()


Jika anda menggunakan obj = Singleton( ) , apa yang anda dapat dengan cara ini bukanlah satu.


Berdasarkan kaedah __new__


Melalui contoh di atas, kita boleh tahu bahawa apabila kita melaksanakan singleton, kita perlu menambah kunci secara dalaman untuk memastikan keselamatan benang.


Kami tahu bahawa apabila kami membuat instantiat objek, kami mula-mula melaksanakan kaedah __new__ kelas (apabila kami tidak menulisnya, object.__new__ dipanggil secara lalai), instantiate objek itu; kemudian laksanakan kelas Kaedah __init__ memulakan objek ini, jadi kita boleh melaksanakan mod tunggal berdasarkan ini.

import threading
class Singleton(object):
 _instance_lock = threading.Lock()
 def __init__(self):
 pass
 def __new__(cls, *args, **kwargs):
 if not hasattr(Singleton, "_instance"):
 with Singleton._instance_lock:
 if not hasattr(Singleton, "_instance"):
 Singleton._instance = object.__new__(cls)
 return Singleton._instance
obj1 = Singleton()
obj2 = Singleton()
print(obj1,obj2)
def task(arg):
 obj = Singleton()
 print(obj)
for i in range(10):
 t = threading.Thread(target=task,args=[i,])
 t.start()

Hasil cetakan adalah seperti berikut:

<__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>
<__main__.Singleton object at 0x038B33D0>

Menggunakan mod singleton ini, apabila membuat instantiation objek pada masa hadapan, kaedah instantiating objek adalah sama seperti biasa obj = Singleton() .


Dilaksanakan berdasarkan metaclass


Pengetahuan berkaitan:


    Kelas dicipta mengikut jenis apabila membuat kelas, taip __init__. Kaedah ini dilaksanakan secara automatik, dan kelas() melaksanakan jenis kaedah __call__ (kaedah __new__ kelas, kaedah __init__ kelas).
  1. Objek dicipta oleh kelas Apabila mencipta objek, kaedah __init__ kelas dilaksanakan secara automatik dan objek() melaksanakan kaedah __call__ kelas.
  2. 例子:
    class Foo:
     def __init__(self):
     pass
     def __call__(self, *args, **kwargs):
     pass
    obj = Foo()
    # 执行type的 __call__ 方法,调用 Foo类(是type的对象)的 __new__方法,用于创建对象,然后调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。
    obj()# 执行Foo的 __call__ 方法
Penggunaan metaclass:

class SingletonType(type):
 def __init__(self,*args,**kwargs):
 super(SingletonType,self).__init__(*args,**kwargs)
 def __call__(cls, *args, **kwargs): # 这里的cls,即Foo类
 print('cls',cls)
 obj = cls.__new__(cls,*args, **kwargs)
 cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)
 return obj
class Foo(metaclass=SingletonType): # 指定创建Foo的type为SingletonType
 def __init__(self,name):
 self.name = name
 def __new__(cls, *args, **kwargs):
 return object.__new__(cls)
obj = Foo('xx')

Melaksanakan mod tunggal:


import threading
class SingletonType(type):
 _instance_lock = threading.Lock()
 def __call__(cls, *args, **kwargs):
 if not hasattr(cls, "_instance"):
 with SingletonType._instance_lock:
 if not hasattr(cls, "_instance"):
 cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
 return cls._instance
class Foo(metaclass=SingletonType):
 def __init__(self,name):
 self.name = name
obj1 = Foo('name')
obj2 = Foo('name')
print(obj1,obj2)

Atas ialah kandungan terperinci Lima cara untuk menulis mod tunggal dalam Python. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:51cto.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam