zoukankan      html  css  js  c++  java
  • [Python自学] 设计模式之单例模式

    一、几种方式实现单例模式

    1.基本版的单例模式

    class Foo(object):
        instance = None
    
        def __init__(self):
            pass
    
        @classmethod
        def get_instance(cls):
            if cls.instance:
                return cls.instance
            else:
                cls.instance = cls()
                return cls.instance
    
        def process(self):
            print("process")
    
    
    if __name__ == '__main__':
        obj1 = Foo.get_instance()
        obj2 = Foo.get_instance()
        print(id(obj1), id(obj2))

    这个版本,我们要使用Foo.get_instance()来获得实例,对用户不友好。

    2.基于__new__实现的单例模式

    class Foo(object):
        instance = None
    
        def __init__(self):
            pass
    
        def __new__(cls, *args, **kwargs):
            if cls.instance:
                return cls.instance
            else:
                cls.instance = object.__new__(cls, *args, **kwargs)
                return cls.instance
    
        def process(self):
            print("process")
    
    
    if __name__ == '__main__':
        obj1 = Foo()
        obj2 = Foo()
        print(id(obj1), id(obj2))

    这个版本,换成了用Foo()来获取实例,和非单例模式是一样的方式,屏蔽了底层细节,对用户友好。

    3.基于模块导入机制实现单例模式

    核心概念:模块只被导入一次

    当我们在导入一个模块时,python会编译生成一个pyc文件,这个文件会在模块的第一次导入时生成。

    当pyc存在的时候,例如第二次导入模块,则不会在运行模块中的代码,而是直接使用内存中的pyc。

    所以,利用这一特性,我们可以构建单例模型:

    # mysingleton.py
    class MySingleton(object):
        def foo(self):
            print("foo...")
    
    
    my_singleton = MySingleton()

    在mysingleton模块中,定义了MySingleton类,并获取了一个实例对象。

    在另一个模块中,对mysingleton模块进行导入:

    # other.py
    
    # 第一次导入my_singleton
    from mysingleton import my_singleton
    # 第二次导入my_singleton
    from mysingleton import my_singleton as my_singleton_2
    
    
    print(id(my_singleton))
    print(id(my_singleton_2))

    输出结果是两个对象的id相同,即两个对象实际上是同一个对象。

    这是因为第一次导入的my_singleton处于内存中,当第二次导入同样的模块时,发现内存中已经存在,则直接引用了内存中的my_singleton对象。

    这样就实现了基于模块的单例模型。

    4.基于装饰器实现的单例模式

    # 实现构建单例对象的装饰器
    def singleton(cls, *args, **kwargs):
        # 一个用于存放单例对象的字典,以类为key,单例对象为value
        instances = {}
    
        def get_instance(*args, **kwargs):
            # 如果这个类没有创建过对象,则创建对象,作为value存放在字典中
            if cls not in instances:
                instances[cls] = cls(*args, **kwargs)
            return instances[cls]
    
        return get_instance
    
    
    @singleton
    class Test(object):
        def __init__(self, name):
            self.name = name
    
        def get_name(self):
            return self.name
    
    
    if __name__ == '__main__':
        t1 = Test("leo1")
        t2 = Test("leo2")
    
        print(t1.get_name())  # 打印leo1
        print(t2.get_name())  # 也打印leo1
        print(id(t1) == id(t2))  # 打印True,说明是同一个对象

    对类使用装饰器,用装饰器来判断类是否已经产生了单例对象,如果没有则创建对象,如果已经存在,则直接返回已经存在的对象。

    二、单例模式示例

    在Django的admin.py中,用于注册model的 admin.site 就是一个单例对象:

    首先,在admin的源码中,导入了site:

    # ACTION_CHECKBOX_NAME is unused, but should stay since its import from here
    # has been referenced in documentation.
    from django.contrib.admin.decorators import register
    from django.contrib.admin.filters import (
        AllValuesFieldListFilter, BooleanFieldListFilter, ChoicesFieldListFilter,
        DateFieldListFilter, FieldListFilter, ListFilter, RelatedFieldListFilter,
        RelatedOnlyFieldListFilter, SimpleListFilter,
    )
    from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
    from django.contrib.admin.options import (
        HORIZONTAL, VERTICAL, ModelAdmin, StackedInline, TabularInline,
    )
    from django.contrib.admin.sites import AdminSite, site
    from django.utils.module_loading import autodiscover_modules
    
    __all__ = [
        "register", "ACTION_CHECKBOX_NAME", "ModelAdmin", "HORIZONTAL", "VERTICAL",
        "StackedInline", "TabularInline", "AdminSite", "site", "ListFilter",
        "SimpleListFilter", "FieldListFilter", "BooleanFieldListFilter",
        "RelatedFieldListFilter", "ChoicesFieldListFilter", "DateFieldListFilter",
        "AllValuesFieldListFilter", "RelatedOnlyFieldListFilter", "autodiscover",
    ]
    
    
    def autodiscover():
        autodiscover_modules('admin', register_to=site)
    
    
    default_app_config = 'django.contrib.admin.apps.AdminConfig'
    View Code

    然后,我们再看site的源码:(在sites.py中)

    class DefaultAdminSite(LazyObject):
        def _setup(self):
            AdminSiteClass = import_string(apps.get_app_config('admin').default_site)
            self._wrapped = AdminSiteClass()
    
    
    # This global object represents the default admin site, for the common case.
    # You can provide your own AdminSite using the (Simple)AdminConfig.default_site
    # attribute. You can also instantiate AdminSite in your own code to create a
    # custom admin site.
    site = DefaultAdminSite()

    可以看到,site是DefaultAdminSite类的一个对象。

    当admin导入了site时,实际上就利用了第三种方式实现的单例模式(基于模块导入实现的单例模式)。

    所以,我们在使用admin.site.register()来注册model的时候,使用的site是一个单例对象:

    #app/admin.py中
    
    admin.site.register(Host, HostConfig)
    admin.site.register(Business)
    admin.site.register(Application)

    6

  • 相关阅读:
    singleton 创建static类型的对象
    记忆曲线 遗忘曲线
    创建classic 得到函数 调用函数
    abstract factory 创建相互关联的类
    log4j PatternLayout
    C#中override重写与new隐藏的区别,以及C#与Java的override区别 转
    iptables如何做内网的https端口映射 转
    得到一棵树 取自表内自递归(即ID 与ParentID)
    Common.TcpLibTcpClientT
    得到汉字的首拼音字符 ZT
  • 原文地址:https://www.cnblogs.com/leokale-zz/p/12222461.html
Copyright © 2011-2022 走看看