python——单例

一、单例模式的介绍

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

场景:

比如,我们用的 Django程序中的settings配置文件,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

 

在 Python 中,我们可以用多种方法来实现单例模式:

  • 使用模块
  • 使用 __ new __
  • 使用装饰器(decorator)
  • 使用元类(metaclass)

基于__new__方法实现

class One(object):
    _instance = None
    def __new__(cls, *args, **kw):
        if not cls._instance:
            cls._instance = object.__new__(cls, *args, **kw)
        return cls._instance

s1=One()
s2=One()
#One类实例化出来的所有对象都是相同的对象

基于模块导入的方式实现 也是最常用的

其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,模块中的代码会执行,同时会生成一个 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。

 

实现单例模式,三个例子:

  • 例一:
//one.py文件
class Person:
   def walk(self,x):
       print(f'向前走{x}米')

wangfei = Person()

 

//two.py文件
#第一次导入
from one import wangfei print(id(wangfei.walk(100)))
#第二次导入
from one import wangfei print(id(wangfei.walk(1000)))
#输出
向前走100米
1721431248
向前走1000米
1721431248

验证了这句:模块中的代码会执行,同时会生成一个 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。

 

 

  • 例二:
//three.py文件
class Person:
    def walk(self,x):
        print(f'向前走{x}米')

wangfei = Person()
//four.py
from three import wangfei,Person
print(id(wangfei))
print(id(Person()))
print(id(Person()))
#输出
1880091761016
1880091620408
1880089942224

导入模块中实例化的对象和导入模块中的类,再通过类实例化得到的对象都是不同的对象。

 

 

  • 例三:
//one.py文件
class Person:
    def walk(self,x):
        print(f'向前走{x}米')

wangfei = Person()
//two.py
from one import wangfei
def func():
    print(id(wangfei))
//three.py
from one import wangfei
from two import func
print(id(wangfei))
func()
#输出
2829704809720
2829704809720

在一个程序中,即便是在不同的py文件中导入同一个对象,它们其实也是同一个对象,第二次导入同样是直接加载第一次导入生成的 .pyc 文件。

 

补充:

单例模式 实现:

  • 类方法
  • 装饰器
  • 基于模块   同上
  • 基于元类

一个类只允许产生一个实例对象

# classmethod 类方法   执行时会把类当作参数传入
class Mysql:
    _instance = None
    def __init__(self,host,port):
        self.host = host
        self.port = port
    @classmethod
    def singleton(cls):
        if not cls._instance:
            cls._instance = cls('127.0.0.1',3306)
        return cls._instance
print(id(Mysql.singleton()))
print(id(Mysql.singleton()))
#输出
2167369923160
2167369923160

 

 装饰器

from functools import wraps
def singleton(cls):
    cls._instance = cls('127.0.0.1',3306)
    @wraps(cls)
    def inner(*args,**kwargs):
        if args or kwargs:    #如果自己有参数就用自己的
            obj = cls(*args,**kwargs)
            return obj
        return cls._instance
    return inner


@singleton  # Mysql = singleton(Mysql)
class Mysql:
    def __init__(self,host,port):
        self.host = host
        self.port = port
obj1 = Mysql()
obj2 = Mysql()
obj3 = Mysql('12342',243)
print(id(obj1),id(obj2),id(obj3))
1872210011640 1872210011640 1872210011696

 

基于元类

class MymetaClass(type):   #写个基类,基类必须继承type类

    def __call__(self, *args, **kwargs):
        if not getattr(self,'_instance'):  #通过反射确认子类没有 _instance 
            self._instance = super().__call__(*args,**kwargs)   #为子类设置_instance方法
        return self._instance

class Mysql(metaclass=MymetaClass):
    _instance = None
    def __init__(self,host,port):
        self.host = host
        self.port = port
print(id(Mysql('127.9.0.1',9090)))
print(id(Mysql('127.9.0.2',9090)))
#输出
1190368475736 1190368475736

 

 

 

 

 

 

 

 

 

posted @ 2019-03-25 21:06  萤huo虫  阅读(124)  评论(0编辑  收藏  举报