面试题2:实现Singleton模式
题目:设计一个类,我们只能生成该类的一个实例。
首先,我们需要知道什么是单例模式(Singleton Pattern),这是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。也就是说,在整个系统中,只允许某个类出现一个实例。
在python中,可以用多种方法来实现单例模式:
- 使用模块
- 使用new
- 使用装饰器(decorator)
- 使用元类(metaclass)
1、使用模块
在python中模块就是天然的单例模式,因为模块在第一次导入时,会生成.pyc文件,当再次导入时,就会直接加载.pyc文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得单例对象。
#mysingleton.py
class Singleton():
def foo(self):
pass
my_singleton =Singleton()
from mysingleton import my_singleton
my_singleton.foo()
2、使用new
先来了解下new,在定义一个类时,使用的最多的就是init,而new和call很少使用到,都知道init方法负责对象的初始化,要想初始化,得先有对象不是,new的作用就是实例化一个对象并返回该实例对象,然后才能被init调用进行初始化。
换个角度说,new是用来创建一个实例对象的,因此我们可以通过修改new方法来使类只出现一个实例,代码如下:
class Singleton():
_instance ={}
def __new__(cls, *args, **kwargs):
if cls not in cls._instance:
cls._instance[cls] =super(Singleton, cls).__new__(cls)
return cls._instance
class MyClass(Singleton):
def __init__(self, val):
self.val =val
if __name__ =='__main__':
a =MyClass(1)
b =MyClass(2)
print(a is b) #True
3、使用装饰器
我们知道,装饰器可以动态的修改一个类或函数的功能,因此也可以使用装饰器来装饰某个类,使其只能生成一个实例。
注意一点,python装饰器被装饰后的函数其实已经是另一个函数(函数名等函数属性会发生改变),为了不影响,python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。
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():
a =1
a =Myclass()
b =Myclass()
print(a is b) #True
4、使用元类
元类(参考:深刻理解python中的元类)是用于创建类对象的类,类对象创建实例对象时一定会调用call方法,因此在调用call时候保证始终只创建一个实例即可,type是python中的一个元类。
class Singleton(type):
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance =super(Singleton, cls).__call__(*args, **kwargs)
return cls._instance
class Foo(metaclass=Singleton):
pass
f1 =Foo()
f2 =Foo()
print(f1 is f2) #True
网友评论