欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python 实现单例模式的一些思考

程序员文章站 2022-06-03 18:59:32
...

一、问题:Python中如何实现单例模式

  单例模式指一个类只能实例化一个对象。

二、解决方案:

  所有资料参考于:

http://python.jobbole.com/87294/

https://www.jianshu.com/p/f63ad9d550f1

https://www.cnblogs.com/tkqasn/p/6524879.html

  1. 模块

  永远只有一次,这让我下意识想到Python 的模块,因为学习的时候就知道,多次模块导入是无效的,都相当于导入一次,因为模块的导入十分消耗资源,若是重复导入那么太低效了。

  因此可以利用 导入模块中的实例来实现这一目标。
  

#singleton.py
class SingleTon:
    def demo(self):
        print('hello world')
singleton = SingleTon()

#test.py
from singleton import singleton
singleton.demo()
  1. new方法

      这里涉及到类实例化过程,我想,要想做到永远实例化一个对象,换句话说只要这个类实例化后就不再实例化,那么我们必须在Python原有实例化过程中“做点手脚”

      那必要的就得现搞清楚实例化的具体过程。

      首先:Foo类的类型是type,Foo 类 也是一个对象,实例化加括号即调用 call方法,而type 就是 Python 内置的元类,通过type类生成Foo类,
      

class Foo:
    def __init__(self):
        print('hello world')
item = Foo()
print(type(Foo),type(item))
#<class 'type'> <class '__main__.Foo'>

然后

  • Foo(*args, **kwargs)等价于Foo.call(*args, **kwargs)
  • 既然Foo是一个type的实例,Foo.call(*args, **kwargs)实际调用的是type.call(Foo,
    *args, **kwargs)

  • type.call(Foo, *args, **kwargs)调用type.new(Foo, *args,
    **kwargs),然后返回一个对象。

  • obj随后通过调用obj.init(*args, **kwargs)被初始化。
  • obj被返回。

可见,new() 方法是创建对象,init() 是初始化,若要解决我们的问题,应该在 前者下功夫,

class Foo:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls,*args,**kwargs)
        return cls._instance


item = Foo()
item1 = Foo()
print(item is item1)
  1. 装饰器

      使用装饰器应该也很方便,wraps 函数 可以保证传入的类的属性不变,
      

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
  1. 元类(metaclass)

str是用来创建字符串对象的类,而int是用来创建整数对象的类,type 是type就是创建类对象的类,元类在API的定义中会有很大用处,具体内容在https://www.cnblogs.com/tkqasn/p/6524879.html讲得很清楚
Django的ORM 就是大量使用元类,有空研究一下。

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

三、挖坑

相关知识点:元类的使用以后研究