在Python中如何实现单例模式?

方法一:使用装饰器实现单例模式。

from functools import wraps


def singleton(cls):
    """单例类装饰器"""
    instances = {}

    @wraps(cls)
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return wrapper


@singleton
class President:
    pass

扩展:装饰器是Python中非常有特色的语法,用一个函数装饰另一个函数或类,只需添加额外的功能。通常通过装饰来实现的功能都属于横切关注功能,跟正常的功能一样业务逻辑没有必然联系,可以动态添加或删除的功能。装饰器可以为提供代码缓存、代理、上下文环境等服务,它是对设计模式中代理模式的践行。在写装饰器的时候,带装饰功能的函数(上面代码中的wrapper函数)通常都会用functools模块中的wraps加上装饰,这个装饰器最重要的作用是给被装饰的类或者函数动态添加一个__wrapped__属性,这个属性附加在被装饰的类之前或函数保留下来的是,这样在我们需要装饰功能的时候,可以通过它来取消装饰器,例如可以使用来President = President.__wrapped__取消对President类做的单例处理。需要提醒大家:上面的单例不是线程安全的的,如果要做到线程安全,需要对创建对象的代码进行加锁的​​处理。在Python中可以使用模块threadingRLock对象来提供锁,可以使用锁对象的acquirerelease方法来实现加锁和解锁的操作。当然,最重要的做法是使用锁对象的with上下文语法来进行隐式的加锁和解锁操作。

方法二:使用元类实现单例模式。

class SingletonMeta(type):
    """自定义单例元类"""

    def __init__(cls, *args, **kwargs):
        cls.__instance = None
        super().__init__(*args, **kwargs)

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


class President(metaclass=SingletonMeta):
    pass

扩展:Python是面向对象的编程语言,在面向对象的世界中,一切皆为对象。对象是通过类来创建的,而类本身也是对象,这样的对象是通过元类来创建的。定义类的时候,如果没有给一个类指定父类,那么默认的父类就是object,如果没有给一个类指定元类,那么默认的元类就是type。通过自定义的元类,我们改变一个类默认的行为,就类似于上面的代码中,我们通过元类的__call__魔术方法,改变了President类的构造器那样。

补充:关于单例模式,在面试中还有可能被问到它的应用场景。通常一个对象的状态是被其他对象共享的,就可以将其设计为单例,例如项目中使用的数据库连接池对象和配置对象通常都是单实例,这样才能保证所有位置获取到的数据库连接和配置信息是完全一致的;并且由于对象只有唯一的实例,因此从根本上避免了创建重复对象造成的时间和空间上面的头,也避免了对资源的占用占用。再举个例子,项目中的日志操作通常会使用单例模式,这是因为共享的日志文件一直处于打开状态,只能有一个实例去操作它,否则在写入日志的时候会产生混乱。

  • 28
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值