day37-2元类,单例模式
元类
- t ype
- 一个造类的对象
- 实例化:元类-->类-->对象
class Foo:
pass
f = Foo()
print(f.__class__)
print(f.__class__.__class__)
<class '__main__.Foo'>
<class 'type'>
造类的第一种形式
- 使用type模仿class关键字造类
class做了什么事
类的三部分
- 类名:
class_name = Foo - 类体代码:
class_body开辟内存空间,把属性和方法放入一个名称空间里 - 父类(基类):
class_bases = (object,)
# eval方法:用来解析某一个具体的数据类型
# eval('[1, 1]') # [1, 1]
# exec方法:会把字符里的代码运行,并且放入名称空间
class_body = '''
count = 1
'''
class_name = 'Foo'
class_bases = (object,) # 加了逗号才是元祖
class_dic = dict()
exec(class_body, {}, class_dic) # {}里是当前所有的内置方法
Foo1 = type(class_name, class_bases, class_dic)
print(Foo1) # Foo1只是变量名,实际上的类名是由class_name定的
print(Foo1.count)
<class '__main__.Foo'>
1
控制元类产生的类
在type和类的中间加一层控制
Foo= Mymeta(class_name, class_bases, class_dic)
用super是为了调用type类里的
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic): # 只是形参,叫什么都可以
# 这里可以对类的属性进行操作,如:
if class_name.islower():
raise TypeError('类名必须大写')
if not class_dic.get('__doc__'): # ''''''的注释在字典中保存键名为__doc__
raise TypeErroe('必须得加注释')
# 方法继承自type
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
class Foo(metaclass=Mymeta): # 把类名,类体代码,父类传递给Mymeta,进而产生类
'''这种注释才有doc'''
def __init__(self, name):
self.name = name
print(Foo)
print(Foo.__class__)
print(Foo.__dict__)
<class '__main__.Foo'>
<class '__main__.Mymeta'> # 实例化出他的类已变成了Mymeta
{'__module__': '__main__', '__doc__': '这种注释才有doc', '__init__': <function Foo.__init__ at 0x0000015E63D7D950>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>}
控制元类产生的对象
实例化类的时候会自动触发
__init__方法,(实际上是触发__new__)实例化对象的时候会自动触发
__call__举例验证:
class Foo():
def __init__(self):
print('init')
def __call__(self, *args, **kwargs):
print('call')
f = Foo()
f()
init
call
- 控制对象产生
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
def __call__(self, *args, **kwargs):
# self就是People, args就是name和x,kwargs没传值
print('self', self)
print(args, kwargs)
# 以下是造对象的过程
# 造一个空类
obj = self.__new__(self) # 造一个空类{},固定写法
print(1, obj.__dict__)
# 造对象
# 相当于调用People.__init__({}, 'leijun', 1)
self.__init__(obj, *args, **kwargs)
# obj就变成了{'name', 'leijun'}
print(2, obj.__dict__)
return obj # 对象实例化
class People(object, metaclass=Mymeta):
def __init__(self, name, x):
self.name = name
P = People('leijun', 1)
self <class '__main__.People'>
('leijun', 1) {}
1 {}
2 {'name': 'leijun'}
实例化类
- 实际上是在调用
__new__
__new__ 和 __init__
- __init__是在初始化类
- __new__是在构造类
class Foo:
def __new__(cls, *args, **kwargs): # 传类
print(cls)
print('new')
return object.__new__(cls) # 这里要用父类,不能用cls,不然会一直循环
def __init__(self):
print('init')
f = Foo()
print(f)
加上元类后类的属性查找顺序
- 对象本身-->类-->父类-->object-->自定义的元类->type找不到报错
- 这里先找object是因为这个类是继承自object的,和元类是两条关系线,找完继承这一条,才会去找元类
- 可以通过类.mro()来查看继承自哪里,只有新式类可以使用

元类控制模版
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
# 这里控制类的产生
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
def __call__(self, *args, **kwargs):
# 这里控制实例化对象时传的参数,由于自己的类中没定义,所以会使用object中的,由于属性的查找顺序,即便在元类中定义了__new__方法,也不会被使用
obj = self.__new__(self) # 建空类,产生一个空对象obj
self.__init__(obj, *args, **kwargs) # 初始化对象obj
# 这里控制对象的产生
return obj
单例模式
- 类用同一种方式调用多个东西时,产生的都是同一个东西
- 目的是为了减少资源开销,当这个类的对象中的数据是共享的时候
1. 使用类方法的特性
NAME = 'leijun'
class People():
__instance = None # 默认值
def __init__(self, name):
self.name = name
@classmethod
def from_conf(cls):
if cls.__instance: # 如果默认值已产生就按默认值,避免二次产生导致id不同
return cls.__instance
cls.__instance = cls(NAME) # 没产生就产生默认值
return cls.__instance
p1 = People.from_conf()
p2 = People.from_conf()
print(id(p1)) # 2242450203144
print(id(p2)) # 2242450203144
2.使用装饰器
NAME = 'leijun'
def deco(cls):
cls.__instance = cls(NAME) # 默认值
def wrapper(*args, **kwargs):
if len(args) == 0 and len(kwargs) == 0: # 没输出就按默认值
return cls.__instance
res = cls(*args, **kwargs)
return res
return wrapper
@deco
class People():
def __init__(self, name):
self.name = name
p1 = People()
p2 = People()
print(id(p1)) # 2458763959432
print(id(p2)) # 2458763959432
3.使用元类
NAME = 'leijun'
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
self.__instance = self(NAME)
def __call__(self, *args, **kwargs):
if len(args) == 0 and len(kwargs) == 0:
return self.__instance
obj = self.__new__(self) # 这是可以用self因为这个self本身没有new方法,所以也要去找父类,就不会出现循环,如果self本身有new,就用父类名,最好是用object
self.__init__(obj, *args, **kwargs)
return obj
class People(metaclass=Mymeta):
def __init__(self, name):
self.name = name
p1 = People()
p2 = People()
print(id(p1))
print(id(p2))
day37-2元类,单例模式的更多相关文章
- 通过 python的 __call__ 函数与元类 实现单例模式
简单一句话,当一个类实现__call__方法时,这个类的实例就会变成可调用对象. 直接上测试代码 class ClassA: def __call__(self, *args, **kwargs): ...
- python中的单例模式、元类
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- python 入门基础24 元类、单例模式
内容目录: 一.元类 二.单例模式 一.元类 1 什么是元类: 源自一句话:在python中,一切皆对象,而对象都是由类实例化得到的 class OldboyTeacher: def __init__ ...
- [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式
使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...
- 深刻理解Python中的元类(metaclass)以及元类实现单例模式
在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...
- Python入门之Python的单例模式和元类
一.单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在. 当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上 ...
- exec , 元类,__new__, __call__ , 单例模式 , 异常
1,类也是对象 ''' 动态语言 可以在运行期间 动态生成类 修改对象属性 静态语言 ''''' ''' type(object_or_name, bases, dict) type(object) ...
- Python元类(metaclass)以及元类实现单例模式
这里将一篇写的非常好的文章基本照搬过来吧,这是一篇在Stack overflow上很热的帖子,我看http://blog.jobbole.com/21351/这篇博客对其进行了翻译. 一.理解类也是对 ...
- 面向对象高级C(元类补充及单例模式)
元类有关知识点补充 #类的名称空间 类的名称空间不能用类似字典的方法修改,例如School类里面有name属性xxx,那么我用School.__dict__['name'] = 'yyy'就会报错&q ...
随机推荐
- python编码小记
Python编码小记 标签(空格分隔): 编程 python 1.list类型remove()操作 列表对象执行remove()函数后,会自动退出循环,所以如果想利用一个单独的for循环删除列表中多个 ...
- 学习笔记——TCP“三次握手”和“四次挥手”,简单介绍
TCP/IP协议中,TCP协议提供可靠的连接服务,采用“三次握手”建立一个连接. (1)第一次握手:客户端发送SYN包(SYN=j)到服务器,并进入SYN_SEND状态,等待服务器确认. (2)第二次 ...
- Sencha Touch 2中如何动态添加button
原理很简单无非就是在一个容器上面选中id,用容器的add方法将button循环加入. 现在我们来试一下 1.先定义一个Container组件用,以后在里面添加button ? 1 2 xtype:'c ...
- Solr插件的弊端
在前文<Solr Update插件自定义条件索引>中,我介绍了如何通过插件的模式,自定义Solr的Update过程.但是在大半年的使用过程中,发现这种方式存在如下弊端. 1.环境难以维护. ...
- Spring MVC-视图解析器(View Resolverr)-多重解析器(Multiple Resolver)示例(转载实践)
以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_multiple_resolver_mapping.htm 说明:示例基于Spri ...
- [转]十五天精通WCF——终结篇 那些你需要注意的坑
终于一路走来,到了本系列的最后一篇了,这一篇也没什么好说的,整体知识框架已经在前面的系列文章中讲完了,wcf的配置众多,如果 不加一些指定配置,你可能会遇到一些灾难性的后果,快来一睹为快吧. 一: 第 ...
- OpenCV+iOS开发使用文档
一. 前言 OpenCV是开源的跨平台的计算机视觉库,实现了图像处理.计算机视觉和机器学习的很多通用算法. 对于移动设备没有快速输入的键盘,大的屏幕,其优势在于图像和声音,因此要 ...
- Hard模式题目
先过一下Hard模式的题目吧. # Title Editorial Acceptance Difficulty Frequency . 65 Valid Number 12.6% Ha ...
- UNP(一):网络编程角度下的TCP、UDP协议
此博文是学习UNP(UNIX Network Programming)后的读书笔记,供以后自己翻阅回想知识. TCP.UDP概述 在前面<计算机网络与TCP/IP>栏目下已经介绍过一些关于 ...
- Python游戏server开发日记(一)目标
到了新的环境.老大让我有空研究下一代server技术,作为一个长期任务. 新的server想达到的目标: 1.分布式系统,对象(Entity)之间的关系类似于Actor模型. 2.逻辑服务,是单进程. ...