元类

  • t ype
  • 一个造类的对象
  • 实例化:元类-->类-->对象
class Foo:
pass f = Foo()
print(f.__class__)
print(f.__class__.__class__)
<class '__main__.Foo'>
<class 'type'>

造类的第一种形式

  • 使用type模仿class关键字造类

class做了什么事

类的三部分

  1. 类名:class_name = Foo
  2. 类体代码:class_body开辟内存空间,把属性和方法放入一个名称空间里
  3. 父类(基类):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元类,单例模式的更多相关文章

  1. 通过 python的 __call__ 函数与元类 实现单例模式

    简单一句话,当一个类实现__call__方法时,这个类的实例就会变成可调用对象. 直接上测试代码 class ClassA: def __call__(self, *args, **kwargs): ...

  2. python中的单例模式、元类

    单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...

  3. python 入门基础24 元类、单例模式

    内容目录: 一.元类 二.单例模式 一.元类 1 什么是元类: 源自一句话:在python中,一切皆对象,而对象都是由类实例化得到的 class OldboyTeacher: def __init__ ...

  4. [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式

    使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...

  5. 深刻理解Python中的元类(metaclass)以及元类实现单例模式

    在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...

  6. Python入门之Python的单例模式和元类

    一.单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在. 当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上 ...

  7. exec , 元类,__new__, __call__ , 单例模式 , 异常

    1,类也是对象 ''' 动态语言 可以在运行期间 动态生成类 修改对象属性 静态语言 ''''' ''' type(object_or_name, bases, dict) type(object) ...

  8. Python元类(metaclass)以及元类实现单例模式

    这里将一篇写的非常好的文章基本照搬过来吧,这是一篇在Stack overflow上很热的帖子,我看http://blog.jobbole.com/21351/这篇博客对其进行了翻译. 一.理解类也是对 ...

  9. 面向对象高级C(元类补充及单例模式)

    元类有关知识点补充 #类的名称空间 类的名称空间不能用类似字典的方法修改,例如School类里面有name属性xxx,那么我用School.__dict__['name'] = 'yyy'就会报错&q ...

随机推荐

  1. Luogu P3740 [HAOI2014] 贴海报 线段树

    线段树版的海报 实际上这个与普通的线段树相差不大,只是貌似数据太水,暴力都可以过啊 本来以为要离散的,结果没打就A了 #include<iostream> #include<cstd ...

  2. 使用git bash向github远程仓库提交代码

    1.登录github,创建仓库. 2.切换到要提交的文件目录下. 3.打开git bash 3.1.初始化仓库 git init 3.2.将本地仓库与远程仓库关联 git remote add ori ...

  3. 使用JQUERY的flexselect插件来实现将SELECT下拉菜单变成自动补全输入框

    这也是下拉列表太长了之后,使用的同事提出来的意见, 然后,本来开始想将DJANGO的那个后台下拉菜单移植过来的,但发现不现实,也麻烦, 就找了几个JQUERY的插件测试了一下,最后选中了flexsel ...

  4. Pie POJ 3122 二分搜索

    Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 17324   Accepted: 5835   Special Judge ...

  5. Spring MVC-集成(Integration)-生成PDF示例(转载实践)

    以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_pdf.htm 说明:示例基于Spring MVC 4.1.6. 以下示例显示如何 ...

  6. www.pgcon.org 文档

    https://www.pgcon.org/2016/schedule/attachments/ https://www.pgcon.org/2015/schedule/attachments/ ht ...

  7. volatile非原子性示例

    volatile非原子性示例 学习了:<Java多线程编程核心技术>高洪岩 著 Page124 package com.stono.thread2.page124_2; public cl ...

  8. [Angular] Using ngTemplateOutlet to create dynamic template

    I can use <tamplete> syntax and a entry component as a container to create a dynamic component ...

  9. 605B. Lazy Student(codeforces Round 335)

    B. Lazy Student time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

  10. 520D

    模拟 很明显应该尽量选最大或最小的数.那么我们维护一个set,再维护一个mp,每次检查是否能选,如果选完这个数上面的东西不悬空就可以选,每次选完都要更新四周-2+2的方块,因为再远就影响不到了 #in ...