单例模式 单例模式(Singleton Pattern) 是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在 。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。
在 Python 中,我们可以用多种方法来实现单例模式:
使用模块
使用 __new__
使用装饰器(decorator)
使用元类(metaclass)
使用__new__
为了使类只能出现一个实例,我们可以使用 __new__
来控制实例的创建过程,代码如下:
1 2 3 4 5 6 7 8 9 10 class Single (object) : _instance = None def __new__ (cls, *args, **kwargs) : if not cls._instance: cls._instance = super(Single,cls).__new__(cls,*args,**kwargs) return cls._instance class Myclass (Single) : a = 1
在上面的代码中,我们将类的实例和一个类变量 _instance
关联起来,如果 cls._instance
为 None 则创建实例,否则直接返回 cls._instance
。
1 2 3 4 5 6 7 8 9 10 11 one = Myclass() two = Myclass() print(one == two) print(one is two) print(id(one),id(two)) --------------------------- True True 2095469450464 2095469450464
使用模块 其实,Python 的模块就是天然的单例模式 ,因为模块在第一次导入时,会生成 .pyc
文件,当第二次导入时,就会直接加载 .pyc
文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块 中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:
1 2 3 4 5 6 class My_Singleton (object) : def foo (self) : pass my_singleton = My_Singleton()
将上面的代码保存在文件 mysingleton.py
中,然后在另一个脚本中这样引用测试:
1 2 3 4 5 6 7 8 9 from mysingleton import my_singletonprint(id(my_singleton),my_singleton.a) my_singleton.a = 5 from mysingleton import my_singletonprint(id(my_singleton),my_singleton.a) ------------------------------------------- 2639945371320 1 2639945371320 5
说明my_singleton是同一个对象,即单例模式
admin执行流程
循环加载执行所有已经注册的app中的admin.py文件
1 2 def autodiscover () : autodiscover_modules('admin' , register_to=site)
执行代码
1 2 3 4 5 6 7 #admin.py class BookAdmin (admin.ModelAdmin) : list_display = ("title" ,'publishDate' , 'price' ) admin.site.register(Book, BookAdmin) admin.site.register(Publish)
admin.site
这里应用的是一个单例模式,对于AdminSite类的一个单例模式,执行的每一个app中的每一个admin.site都是一个对象
执行register方法
1 2 3 4 5 6 7 8 9 10 11 admin.site.register(Book, BookAdmin) admin.site.register(Publish) class ModelAdmin (BaseModelAdmin) :pass def register (self, model_or_iterable, admin_class=None, **options) : if not admin_class: admin_class = ModelAdmin self._registry[model] = admin_class(model, self)
admin\site.py 部分源码
1 2 3 4 5 6 7 8 9 def register (self, model_or_iterable, admin_class=None, **options) : if not admin_class: admin_class = ModelAdmin ……………… self._registry[model] = admin_class(model, self)
如果没有指定admin_class,就默认使用ModelAdmin,然后最后把注册的model 以model本身为键,admin_class为值 加入到_registry这个字典中(registry初始为空字典)
1 2 3 4 5 6 7 8 admin.site.register(Book) admin.site.register(Author) admin.site.register(Publish) print(admin.site._registry) ------------------------------------------------------------------- {<class 'django .contrib .auth .models .Group '>: <django.contrib.auth.admin.GroupAdmin object at 0x0000018D47B4ACC0 >, <class 'django .contrib .auth .models .User '>: <django.contrib.auth.admin.UserAdmin object at 0x0000018D47B75898 >, <class 'copyadmin .models .Book '>: <django.contrib.admin.options.ModelAdmin object at 0x0000018D47B758D0 >, <class 'copyadmin .models .Author '>: <django.contrib.admin.options.ModelAdmin object at 0x0000018D47B759E8 >, <class 'copyadmin .models .Publish '>: <django.contrib.admin.options.ModelAdmin object at 0x0000018D47B75A58 >}
到这里admin的注册流程结束!
admin的url配置
1 2 3 urlpatterns = [ url(r'^admin/' , admin.site.urls), ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class AdminSite (object) : def get_urls (self) : from django.conf.urls import url, include urlpatterns = [] valid_app_labels = [] for model, model_admin in self._registry.items(): urlpatterns += [ url(r'^%s/%s/' % (model._meta.app_label, model._meta.model_name), include(model_admin.urls)), ] if model._meta.app_label not in valid_app_labels: valid_app_labels.append(model._meta.app_label) return urlpatterns @property def urls (self) : return self.get_urls(), 'admin' , self.name
主要利用url分发的方式。动态构造分发的url列表
循环self._registry
也就是admin.site._registry
列表中的每个项,构造出app名称+model名称url
url方法拓展,简单分发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from django.shortcuts import HttpResponsedef test01 (request) : return HttpResponse("test01" ) def test02 (request) : return HttpResponse("test02" ) urlpatterns = [ url(r'^admin/' , admin.site.urls), url(r'^yuan/' , ([ url(r'^test01/' , test01), url(r'^test02/' , test02), ],None ,None )), ]
模拟admin方式设计url 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 def show (request) : return HttpResponse("show" ) def add (request) : return HttpResponse("add" ) def delete (request) : return HttpResponse("delete" ) def change (request) : return HttpResponse("change" ) def get_action_urls () : action_url = [ url(r'^$' ,show), url(r'^add/' ,add), url(r'^del/' ,delete), url(r'^change/' ,change) ] return action_url, None , None def get_urls () : tempurl = [] for model,model_admin in admin.site._registry.items(): tempurl.append(url(r'^{}/{}/' .format(model._meta.app_label,model._meta.model_name),get_action_urls())) return tempurl,None ,None urlpatterns = [ url(r'^admin/' , admin.site.urls), url(r'^test/' , get_urls()), ]
构成的url
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ^admin/ ^test/ ^auth/group/ ^add/ ^test/ ^auth/group/ ^del/ ^test/ ^auth/group/ ^change/ ^test/ ^auth/user/ ^test/ ^auth/user/ ^add/ ^test/ ^auth/user/ ^del/ ^test/ ^auth/user/ ^change/ ^test/ ^copyadmin/book/ ^test/ ^copyadmin/book/ ^add/ ^test/ ^copyadmin/book/ ^del/ ^test/ ^copyadmin/book/ ^change/ ^test/ ^copyadmin/author/ ^test/ ^copyadmin/author/ ^add/ ^test/ ^copyadmin/author/ ^del/ ^test/ ^copyadmin/author/ ^change/ ^test/ ^copyadmin/publish/ ^test/ ^copyadmin/publish/ ^add/ ^test/ ^copyadmin/publish/ ^del/ ^test/ ^copyadmin/publish/ ^change/
组件对应设计 demo项目文件目录格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 modelDemo/ ├── app01 │ ├── __init__.py │ ├── __pycache__ │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── __init__.py │ │ └── __pycache__ │ ├── models.py │ ├── tests.py │ ├── views.py │ └── yadmin.py ├── app02 │ ├── __init__.py │ ├── __pycache__ │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── __init__.py │ │ └── __pycache__ │ ├── models.py │ ├── tests.py │ ├── views.py │ └── yadmin.py ├── db.sqlite3 ├── manage.py ├── modelDemo │ ├── __init__.py │ ├── __pycache__ │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── templates └── yadmin ├── __init__.py ├── __pycache__ ├── admin.py ├── apps.py ├── migrations │ ├── __init__.py │ └── __pycache__ ├── models.py ├── service │ ├── __init__.py │ ├── __pycache__ │ └── yadmin.py ├── tests.py └── views.py
yadmin / service / yadmin.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 from django.http import HttpResponsefrom django.conf.urls import urlclass Modelyadmin (object) : def __init__ (self,model,site) : self.model = model self.site = site def list_view (self,request) : return HttpResponse("list" ) def add_view (self,request) : return HttpResponse("add" ) def delete_view (self,request) : return HttpResponse("delete" ) def change_view (self,request) : return HttpResponse("change" ) def get_action_urls (self) : action_url = [ url(r'^$' , self.list_view), url(r'^add/' , self.add_view), url(r'^del/' , self.delete_view), url(r'^change/' , self.change_view) ] return action_url @property def action_urls (self) : return self.get_action_urls(),None ,None class yadminSite (object) : def __init__ (self,name='admin' ) : self._registry = {} def register (self,model,admin_class=None,**options) : if not admin_class: admin_class = Modelyadmin self._registry[model] = admin_class(model,self) def get_urls (self) : tempurl = [] for model, model_admin in self._registry.items(): app_label = model._meta.app_label model_name = model._meta.model_name tempurl.append(url(r'^{0}/{1}/' .format(app_label, model_name), model_admin.action_urls)) return tempurl @property def urls (self) : return self.get_urls(),None ,None site = yadminSite()
简单设计注册组件和url分发设计
yadmin / apps.py
1 2 3 4 5 6 7 8 9 10 11 from django.apps import AppConfigfrom django.utils.module_loading import autodiscover_modulesclass YadminConfig (AppConfig) : name = 'yadmin' def ready (self) : autodiscover_modules('yadmin' )