元类

  • 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))

最新文章

  1. DOTA 2 Match History WebAPI(翻译)
  2. 用Merge来改写相关更新的例子
  3. caffe中的props
  4. arcgis server 10.2安装后,忘记Manager的用户名和密码
  5. HDU 1171 Big Event in HDU --暴力+生成函数
  6. (二)如何在.net中使用Redis
  7. URAL - 1736 - Chinese Hockey
  8. dedecms修改templets为别的名字
  9. WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化
  10. vim ctl+v批量添加/删除
  11. Ubuntu系统上安装搜狗拼音输入法sogou
  12. FATAL ERROR: please install the following Perl modules before executing
  13. 2019年桌面Linux需要做好的7件事
  14. Vue原理--虚拟DOM
  15. 砝码组合(dfs)
  16. Ubuntu上Qt之简单图片浏览器
  17. qt小程序
  18. HTML5之美
  19. docker 的简单操作
  20. 将string str中的str转换成字符数组

热门文章

  1. GIT的API主要应用示例
  2. firedac的TFDStoredProc动态创建并调用存储过程
  3. SSH框架之Struts(3)——Struts的执行流程之核心方法
  4. hiho challenge 15 C题
  5. Jmeter压测问题_Non HTTP response code: org.apache.http.conn.ConnectTimeoutException
  6. poj3296--Rinse(三分)
  7. Android 线程 Looper.prepare()、Looper.loop() 使用
  8. UI设计---&amp;gt;全心全意为人民服务的宗旨----&amp;gt;注重客户体验---&amp;gt;软件持久的生命力
  9. 一步步玩pcDuino3--mmc下的bootloader
  10. hdu 1532 Drainage Ditches(最大流)